/*
 *    ### 前端开发JS工具类函数(YHBTool) ###
 *    @author ：王劲翔
 *    @describe：此JS文件是用来保存工具类函数或者表达式的
 *    @import：下载该JS文件，并在HTML中引入该JS文件即可
 */

let __YHBToolIsMobile = false
// let __YHBToolMobileBaseSize = 375
/**
 * 用来将元素创建模式切换为手机端
 * @param {移动端基础设计尺寸} baseSize
 */
function SwitchToMobile (baseSize = 375) {
  __YHBToolIsMobile = true
  // __YHBToolMobileBaseSize = baseSize
}
/**
 * 用来将元素创建模式切换为电脑端
 */
function SwitchToComputer () {
  __YHBToolIsMobile = false
}

let __YHBToolUserInputInputStr = ''
/**
 * prompt方法，文字输入限制
 */
const userInput = {
  /**
   * 禁止输入空字符串
   * @param {输入框提示文字} promptInfo String
   * @param {空输入提示文字} errInfoNull String
   * @returns String
   */
  Null: function (promptInfo = '', errInfoNull = '') {
    if (!promptInfo) promptInfo = '请输入：'
    if (!errInfoNull) errInfoNull = '输入为空！'
    for (let i = true; i; '') {
      __YHBToolUserInputInputStr = prompt(promptInfo)
      !__YHBToolUserInputInputStr ? alert(errInfoNull) : (i = false)
    }
    return __YHBToolUserInputInputStr
  },
  /**
   * 仅可以输入给定的数组内容
   * @param {存放内容的数组} arr Array
   * @param {输入框提示文字} promptInfo String
   * @param {输入字符非数组内容提示文字} errQualifiedInfo String
   * @param {空输入提示文字} errInfoNull String
   * @returns String
   */
  ArrLimit: function (
    arr = [],
    promptInfo = '',
    errQualifiedInfo = '',
    errInfoNull = ''
  ) {
    if (!promptInfo) promptInfo = '请输入：'
    if (!errQualifiedInfo) errQualifiedInfo = '非限定字符！'
    if (!errInfoNull) errInfoNull = '输入为空！'
    for (let i = true; i; '') {
      __YHBToolUserInputInputStr = prompt(promptInfo)
      if (!__YHBToolUserInputInputStr) {
        alert(errInfoNull)
      } else {
        for (let j = 0; j < arr.length; j++) {
          if (__YHBToolUserInputInputStr === arr[j] + '') {
            i = false
            break
          }
        }
        if (i) alert(errQualifiedInfo)
      }
    }
    return __YHBToolUserInputInputStr
  },
  /**
   * 仅允许输入数字
   * @param {输入框提示文字} promptInfo String
   * @param {非数字提示文字} errInfoNaN String
   * @param {空输入提示文字} errInfoNull String
   * @returns Number
   */
  Number: function (
    promptInfo = '',
    errInfoNaN = '',
    errInfoNull = ''
  ) {
    if (!promptInfo) promptInfo = '请输入数字：'
    if (!errInfoNaN) errInfoNaN = '非数字！'
    if (!errInfoNull) errInfoNull = '输入为空！'
    for (let i = true; i;) {
      __YHBToolUserInputInputStr = prompt(promptInfo)
      !__YHBToolUserInputInputStr
        ? alert(errInfoNull)
        : +__YHBToolUserInputInputStr ||
          +__YHBToolUserInputInputStr + 1
            ? (i = false)
            : alert(errInfoNaN)
    }
    return +__YHBToolUserInputInputStr
  },
  /**
   * 仅允许输入限定范围的数字
   * @param {数字范围下限} min Number
   * @param {数字范围上限} max Number
   * @param {输入框提示文字} promptInfo String
   * @param {非范围数字提示文字} errScopeInfo String
   * @param {非数字提示文字} errInfoNaN String
   * @param {空输入提示文字} errInfoNull String
   * @returns Number
   */
  NumberScope: function (
    min = 0,
    max = 1,
    promptInfo = '',
    errScopeInfo = '',
    errInfoNaN = '',
    errInfoNull = ''
  ) {
    if (!promptInfo) promptInfo = '请输入数字：'
    if (!errScopeInfo) errScopeInfo = '超过数字范围！'
    if (!errInfoNaN) errInfoNaN = '非数字！'
    if (!errInfoNull) errInfoNull = '输入为空！'
    for (let i = true; i;) {
      __YHBToolUserInputInputStr = prompt(promptInfo)
      !__YHBToolUserInputInputStr
        ? alert(errInfoNull)
        : +__YHBToolUserInputInputStr ||
          +__YHBToolUserInputInputStr + 1
            ? +__YHBToolUserInputInputStr > max ||
          +__YHBToolUserInputInputStr < min
                ? alert(errScopeInfo)
                : (i = false)
            : alert(errInfoNaN)
    }
    return +__YHBToolUserInputInputStr
  }
}
let __YHBToolIsFloatHTML = false
/**
 * console.log 简化版
 * @param {控制台输出信息} logMsg
 */
const log = function (logMsg = '') {
  console.log(logMsg)
}
/**
 * console.dir 简化版
 * @param {控制台输出信息} dirMsg
 */
const dir = function (dirMsg = '') {
  console.dir(dirMsg)
}
/**
 * console.error 简化版
 * @param {控制台输出信息} errMsg
 */
const err = function (errMsg = '') {
  console.error(errMsg)
}
/**
 * console.log方法，控制台打印输出
 */
const $Log = {
  /**
   * 将数组内容依次打印在控制台
   * @param {存放打印内容的数组} arr Array
   */
  Line: function (arr = []) {
    for (let i = 0; i < arr.length; i++) {
      console.log(arr[i])
    }
  },
  /**
   * 打印指定颜色的内容到控制台
   * @param {打印内容} info String
   * @param {颜色} color String
   * @param {背景颜色} backgroundColor String
   */
  Color: function (info = '', color = '', backgroundColor = '') {
    backgroundColor
      ? console.log(
        '%c%s',
          `color:${color};background:${backgroundColor}`,
          info
      )
      : console.log('%c' + info, `color:${color}`)
  },

  /**
   * 浮窗控制台收放图标
   * 已有方法对其调用
   */
  rightIcon:
    '<svg t="1695961394065" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3991" width="20" height="20"><path d="M512 960c-247.039484 0-448-200.960516-448-448S264.960516 64 512 64 960 264.960516 960 512 759.039484 960 512 960zM512 128c-211.744443 0-384 172.255557-384 384s172.255557 384 384 384 384-172.255557 384-384S723.744443 128 512 128z" fill="#aefbf6" p-id="3992"></path><path d="M668.832254 501.152426c-0.032684-0.127295-0.192662-0.25631-0.25631-0.383604-1.536138-3.615858-3.648542-7.071738-6.591802-10.047682-0.032684-0.032684-0.063647-0.032684-0.096331-0.063647-0.032684-0.032684-0.032684-0.063647-0.063647-0.096331l-158.911974-159.359226c-12.480043-12.512727-32.735385-12.576374-45.248112-0.063647-12.512727 12.480043-12.54369 32.735385-0.063647 45.248112l136.287918 136.671523-137.407768 135.904314c-12.576374 12.447359-12.672705 32.671738-0.25631 45.248112 6.239161 6.335493 14.496116 9.504099 22.751351 9.504099 8.12794 0 16.25588-3.103239 22.496761-9.247789l160.25545-158.495686C671.231931 526.592447 673.600645 512.767209 668.832254 501.152426z" fill="#aefbf6" p-id="3993"></path></svg>',

  /**
   * 浮窗控制台清空图标
   * 已有方法对其调用
   */
  clearIcon:
    '<svg t="1696315613716" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4221" width="200" height="200"><path d="M384 298.666667V128q0-35.328 25.002667-60.330667T469.333333 42.666667h85.333334q35.328 0 60.330666 25.002666T640 128v170.666667h-42.666667V256h202.922667q28.245333 0 50.944 16.853333 22.656 16.896 30.805333 43.946667l38.4 128q12.288 41.088-13.269333 75.477333-25.6 34.389333-68.48 34.389334H185.344q-42.88 0-68.48-34.389334-25.6-34.389333-13.226667-75.477333l38.4-128q8.106667-27.050667 30.762667-43.946667Q195.498667 256 223.744 256H426.666667v42.666667H384z m85.333333 0q0 4.181333-0.853333 8.32-0.768 4.138667-2.389333 8.021333-1.621333 3.84-3.968 7.381333-2.304 3.456-5.290667 6.442667-2.986667 2.986667-6.442667 5.290667-3.498667 2.346667-7.381333 3.968-3.882667 1.621333-8.021333 2.432Q430.848 341.333333 426.666667 341.333333H223.744l-38.4 128h653.312l-38.4-128H597.333333q-4.224 0-8.32-0.853333-4.138667-0.768-8.021333-2.389333-3.84-1.621333-7.381333-3.968-3.498667-2.304-6.442667-5.290667-2.986667-2.986667-5.333333-6.442667-2.304-3.498667-3.925334-7.381333-1.621333-3.882667-2.432-8.021333Q554.666667 302.848 554.666667 298.666667V128h-85.333334v170.666667z" fill="#ffffff" p-id="4222"></path><path d="M862.08 868.565333q12.586667-114.602667 12.586667-190.634666 0-103.424-23.253334-178.56-0.981333-3.242667-2.474666-6.272-1.536-3.029333-3.498667-5.802667-1.962667-2.773333-4.352-5.205333-2.389333-2.432-5.12-4.437334-2.730667-2.005333-5.717333-3.584-3.029333-1.536-6.272-2.602666-3.2-1.066667-6.570667-1.578667Q814.08 469.333333 810.666667 469.333333H192q-4.181333 0-8.32 0.853334-4.138667 0.768-8.021333 2.389333-3.84 1.621333-7.381334 3.968-3.456 2.304-6.442666 5.290667-2.986667 2.986667-5.290667 6.442666-2.346667 3.498667-3.968 7.381334-1.621333 3.882667-2.432 8.021333-0.810667 4.138667-0.810667 8.32v1.664q2.645333 67.541333 0 163.072-1.706667 63.36-71.509333 169.258667-28.544 43.306667-4.138667 89.173333Q98.261333 981.333333 150.4 981.333333h585.344q48.384 0 84.608-32.170666 36.437333-32.384 41.728-80.64zM777.813333 554.666667q11.562667 53.333333 11.562667 123.264 0 71.338667-12.074667 181.333333-1.706667 15.573333-13.568 26.112-11.946667 10.624-27.946666 10.624H150.357333q-0.853333 0-1.322666-0.896-0.597333-1.152 0.042666-2.133333 83.2-126.208 85.589334-213.888 1.877333-69.12 1.109333-124.416h541.994667z" fill="#ffffff" p-id="4223"></path><path d="M333.056 963.882667Q426.666667 836.309333 426.666667 682.666667H341.333333q0 125.653333-77.056 230.784l68.778667 50.432zM594.730667 953.344Q640 829.866667 640 682.666667h-85.333333q0 132.053333-40.064 241.322666l80.128 29.354667z" fill="#ffffff" p-id="4224"></path></svg>',
  /**
   * 浮窗型控制台，将控制台移动到页面上
   * @param {控制台打印消息} msg
   */
  Float: function (msg = '') {
    if (!__YHBToolIsFloatHTML) {
      const div = document.createElement('div')
      const divHeader = document.createElement('div')
      const h5 = document.createElement('h5')
      const input = document.createElement('input')
      const p = document.createElement('p')
      const span = document.createElement('span')
      const spanClear = document.createElement('span')
      div.classList.add("__YHBToolLogFloatDivBox")
      input.type = 'type'
      input.placeholder = '控制台'
      p.classList.add('__YHBToolLogFloatText')
      span.innerHTML = this.rightIcon
      spanClear.innerHTML = this.clearIcon
      h5.innerHTML = '浮窗型打印控制台'
      h5.onselectstart = () => false
      div.appendChild(h5)
      div.appendChild(divHeader)
      div.appendChild(span)
      div.appendChild(spanClear)
      div.appendChild(input)
      div.appendChild(p)
      css.style(div, {
        height: window.innerHeight * 0.9 + 'px',
        width: '350px',
        position: 'fixed',
        right: '10px',
        top: '50%',
        transform: 'translateY(-50%)',
        padding: '15px',
        backgroundColor: 'rgba(0,0,0,0.8)',
        borderRadius: '15px',
        boxSizing: 'border-box',
        overflow: 'hidden',
        zIndex: '99999999999999999999999999999999999',
        justifyContent: 'center',
        alignItems: 'center',
        flexWrap: 'wrap',
        display: 'flex'
      })
      css.styles(divHeader, {
        position: 'absolute',
        top: '0px',
        width: '100%',
        height: '46px',
        backgroundColor: 'rgba(0,0,0,0)'
      })
      css.styles(h5, {
        textAlign: 'center',
        width: '100%',
        fontSize: '18px',
        color: 'white',
        paddingBottom: '5px',
        borderBottom: '1px solid',
        cursor: 'default'
      })
      css.style(input, {
        marginTop: '5px',
        padding: '0px 5px',
        height: '20px',
        width: '100%',
        border: 'none',
        backgroundColor: '#b9b9b9e0',
        borderRadius: '5px',
        outline: 'unset'
      })
      css.styles(p, {
        width: '100%',
        height:"80%",
        fontSize: '13px',
        color: 'white',
        wordWrap: 'break-word',
        transition: 'all 0.2s',
        overflowY:'auto',
        position: 'relative',
      })
      css.style(spanClear, {
        height: '20px',
        width: '20px',
        position: 'absolute',
        top: '0',
        right: '0',
        transform: 'translate(-50%,50%)',
        justifyContent: 'center',
        alignItems: 'center',
        cursor: 'pointer',
        overflow: 'hidden',
        display: 'flex'
      })
      css.style(span, {
        height: '20px',
        width: '20px',
        position: 'absolute',
        top: '0',
        left: '0',
        transform: 'translate(50%,50%)',
        justifyContent: 'center',
        alignItems: 'center',
        cursor: 'pointer',
        overflow: 'hidden',
        display: 'flex'
      })
      let isContract = false
      let isInput = false
      divHeader.onmousedown = function (e) {
        const boxLeft = e.offsetX
        const boxTop = e.offsetY
        document.onmousemove = function (e) {
          div.style.position = 'absolute'
          div.style.transform = ''
          div.style.left = e.clientX - boxLeft + 'px'
          div.style.top = e.clientY - boxTop + 'px'
        }
        document.onmouseup = function () {
          document.onmousemove = null
        }
      }
      Listener(input, 'mouseover', item => {
        item.style.backgroundColor = 'rgb(255 255 255 / 94%)'
      })
      Listener(input, 'mouseout', item => {
        item.style.backgroundColor = '#b9b9b9e0'
      })
      Listener(input, { keydown: 'Enter' }, () => {
        isInput = true
        console.log(input.value)
      })
      Listener(span, 'click', () => {
        if (isContract) {
          div.style.width = '350px'
          p.style.display = 'block'
          h5.style.display = 'block'
          input.style.display = 'block'
          spanClear.style.display = 'flex'
          span.style.transform = 'translate(50%,50%) rotate(0deg)'
        } else {
          div.style.width = 0
          p.style.display = 'none'
          h5.style.display = 'none'
          input.style.display = 'none'
          spanClear.style.display = 'none'
          span.style.transform = 'translate(30%,50%) rotate(180deg)'
        }
        isContract = !isContract
      })
      Listener(spanClear, 'click', () => {
        p.innerHTML = ''
      })
      const errDiv = document.createElement('div')
      const errTitle = document.createElement('p')
      const errMsg = document.createElement('a')
      const errTypeTitle = document.createElement('p')
      const errType = document.createElement('p')
      const errFromTitle = document.createElement('p')
      const errFrom = document.createElement('p')
      const errFromA = document.createElement('a')
      const errLine = document.createElement('p')
      const errEnd = document.createElement('p')
      errTitle.innerText =
        '- - - - - - - - 【 异常信息 】 - - - - - - - -\n\n'
      errTypeTitle.innerText = '\n** 异常类型 **'
      errFromTitle.innerText = '\n** 异常来源文件 **'
      errEnd.innerText =
        '\n- - - - - - - - - - - - - - - - - - - - - - - - - -'
      errFromA.href = 'javascript:;'
      errDiv.appendChild(errTitle)
      errDiv.appendChild(errMsg)
      errDiv.appendChild(errTypeTitle)
      errDiv.appendChild(errType)
      errDiv.appendChild(errFromTitle)
      errFrom.appendChild(errFromA)
      errDiv.appendChild(errFrom)
      errDiv.appendChild(errLine)
      errDiv.appendChild(errEnd)
      css.style(errDiv, {
        width: '100%',
        backgroundColor: '#330000ab',
        borderRadius: '10px',
        padding: '10px 10px',
        boxSizing: 'border-box',
        marginBottom: '10px'
      })
      css.style(errTitle, {
        width: '100%',
        textAlign: 'center',
        color: '#ff5a5a',
        fontWeight: '700',
        fontSize: '13px'
      })
      css.style(errMsg, {
        display: 'block',
        width: '100%',
        textAlign: 'center',
        color: '#ff8d8d',
        fontWeight: '700',
        fontSize: '13px',
        textDecoration: 'none',
        wordWrap: 'break-word'
      })
      css.style(errTypeTitle, {
        width: '100%',
        textAlign: 'center',
        color: '#ff5a5a',
        fontWeight: '700',
        fontSize: '13px'
      })
      css.style(errType, {
        width: '100%',
        textAlign: 'center',
        color: '#ff5a5a'
      })
      css.style(errFromTitle, {
        width: '100%',
        textAlign: 'center',
        color: '#ff5a5a',
        fontWeight: '700',
        fontSize: '13px'
      })
      css.style(errFrom, {
        width: '100%',
        textAlign: 'center'
      })
      css.style(errFromA, {
        textDecoration: 'none',
        color: '#8cc2ff'
      })
      css.style(errLine, {
        width: '100%',
        textAlign: 'center',
        color: '#ff5a5a',
        fontWeight: '700',
        fontSize: '13px'
      })
      css.style(errEnd, {
        width: '100%',
        textAlign: 'center',
        color: '#ff5a5a',
        fontWeight: '700',
        fontSize: '13px'
      })
      document.body.appendChild(div)
      css.scrollbar(".__YHBToolLogFloatText", {
        width: 0,
        track: {
          width: 0,
        }
      })
      // 获取行数
      function getStackTrace () {
        const obj = {}
        Error.captureStackTrace(obj, getStackTrace)
        let stack = obj.stack
        stack = stack.slice(stack.lastIndexOf('/') + 1, stack.length)
        const str = []
        str[0] = stack.slice(0, stack.indexOf(':'))
        str[1] = stack.slice(
          stack.indexOf(':') + 1,
          stack.lastIndexOf(':')
          )
        str[2] = stack.slice(stack.lastIndexOf(':'), stack.length)
        return str
      }
      //错误类型映射表
      const errTable = {
        SyntaxError:"语法错误",
        TypeError:"类型错误",
        ReferenceError:"引用错误",
        RangeError:"范围错误",
        URIError:"URI错误",
        EvalError:"Eval错误",
        InternalError:"内部错误",
      }
      //根据str返回错误类型
      function getErrText(str) { 
        for (const key in errTable) {
          if (key === str) { return errTable[key]}
        }
        return "未定义类型的错误"
      }
      __YHBToolIsFloatHTML = true
      console.log = function (msg) {
        if (isInput) {
          let rel = evalSimulate(msg)
          if (typeof evalSimulate('(' + msg + ')') === 'object') {
            rel = evalSimulate('(' + msg + ')')
          }
          if (typeof rel === 'number') {
            p.innerHTML += `<p style="width: 100%;background-color: #00000082;color:#ffdd00">控制台： ${
              msg + ' --> '
            }<span style="color:#7980ea">${rel}</span></p>`
          } else if (typeof rel === 'boolean') {
            p.innerHTML += `<p style="width: 100%;background-color: #00000082;color:#ffdd00">控制台： ${
              msg + ' --> '
            }<span style="color:#9197ea">${rel}</span></p>`
          } else if (rel instanceof Array) {
            p.innerHTML += `<p style="margin-bottom:5px;border-radius:5px;width: 100%;background-color: #00000082;color:#ffdd00">控制台： ${
              msg + ' --> '
            }<span style="color:#51c7ff">${_expandMsg(
              rel
            )}</span></p>`
          } else if (rel instanceof Object) {
            p.innerHTML += `<p style="margin-bottom:5px;border-radius:5px;width: 100%;background-color: #00000082;color:#ffdd00">控制台： ${
              msg + ' --> '
            }<span style="color:#85fb7b">${_expandMsg(
              rel
            )}</span></p>`
          } else {
            p.innerHTML += `<p style="width: 100%;background-color: #00000082;color:#ffdd00">控制台： ${
              msg + ' --> '
            }<span style="color:#fff">${rel}</span></p>`
          }
          isInput = false
          input.value = ''
          p.scrollTop = p.scrollHeight
        } else {
          const line = getStackTrace()
          if (typeof msg === 'number') {
            p.innerHTML += `<p style="color:#7980ea">${msg}<p style="color:#78dce0;width:100%;text-align:right;">来自${line[0]}文件 第${line[1]}行 - 数字</p></p>`
          } else if (typeof msg === 'boolean') {
            p.innerHTML += `<p style="color:#9197ea">${msg}<p style="color:#78dce0;width:100%;text-align:right;">来自${line[0]}文件 第${line[1]}行 - 布尔</p></p>`
          } else if (msg instanceof Array) {
            p.innerHTML += `<p style="margin-bottom:5px;border-radius:5px;background-color: #00000063;color:#51c7ff">${_expandMsg(
              msg
            )}<p style="color:#78dce0;width:100%;text-align:right;">来自${
              line[0]
            }文件 第${line[1]}行 - 数组</p></p>`
          } else if (msg instanceof Object) {
            p.innerHTML += `<p style="margin-bottom:5px;border-radius:5px;background-color: #00000052;color:#85fb7b">${_expandMsg(
              msg
            )}<p style="color:#78dce0;width:100%;text-align:right;">来自${
              line[0]
            }文件 第${line[1]}行 - 对象</p></p>`
          } else if (Is.Error(msg)) {
            p.innerHTML += `<p style="color:#ff4343">${msg}<p style="color:#78dce0;width:100%;text-align:right;">来自${line[0]}文件 第${line[1]}行 - 异常</p></p>`
          }else {
            p.innerHTML += `<p>${msg}<p style="color:#78dce0;width:100%;text-align:right;">来自${line[0]}文件 第${line[1]}行 - 字符串</p></p>`
          }
        }
        p.scrollTop = p.scrollHeight
        function _expandMsg (msg, num = 1) {
          let temp = ''
          // 数组
          if (msg instanceof Array) {
            temp = `(${msg.length}) [<br/>`
            for (let i = 0; i < msg.length; i++) {
              if (typeof msg[i] === 'function') {
                temp += `${nbspNum(
                  num
                )}${i}: <span style="color:#e73bd7;font-weight: 700;">function()</span>,<br/>`
              } else if (msg[i] instanceof Object) {
                temp += `${nbspNum(num)}${i}: ${_expandMsg(
                  msg[i],
                  num + 1
                )},<br/>`
              } else if (typeof msg[i] === 'string') {
                temp += `${nbspNum(num)}${i}: "${msg[i]}",<br/>`
              } else {
                temp += `${nbspNum(num)}${i}: ${msg[i]},<br/>`
              }
            }
            temp =
              temp.substring(0, temp.length - 6) +
              `<br/>${nbspNum(num - 1)}]`
          } else if (msg instanceof Object) {
            // 对象
            temp = '{<br/>'
            for (const key in msg) {
              if (typeof msg[key] === 'function') {
                temp += `${nbspNum(
                  num
                )}${key}: <span style="color:#e73bd7;font-weight: 700;">function()</span>,<br/>`
              } else if (msg[key] instanceof Array) {
                temp += `${nbspNum(num)}${key}: ${_expandMsg(
                  msg[key],
                  num + 1
                )},<br/>`
              } else if (typeof msg[key] === 'string') {
                temp += `${nbspNum(num)}${key}: "${msg[key]}",<br/>`
              } else {
                temp += `${nbspNum(num)}${key}: ${msg[key]},<br/>`
              }
            }
            temp =
              temp.substring(0, temp.length - 6) +
              `<br/>${nbspNum(num - 1)}}`
          }
          // 对齐空格
          function nbspNum (num) {
            let str = ''
            for (let i = 0; i < num; i++) {
              str += '&nbsp&nbsp&nbsp&nbsp'
            }
            return str
          }
          return temp
        }
      }
      console.dir = function (msg) {
        let objOpen = ''
        if (typeof msg !== 'string') {
          for (const key in msg) {
            let str = msg[key].toString()
            let type = typeof msg[key]
            if (type === 'function') {
              str = str.substring(8, str.indexOf('{'))
            }
            if (type === 'object') {
              type = Object.prototype.toString.call(msg[key])
            }
            str = `<span style='color:#5c5cff;'>${type} </span>${str}`
            objOpen += `<span style="color:#3cedff;font-weight: 700;font-size:12px">${key}</span>: ${str}<br />`
          }
        } else {
          objOpen += msg
        }
        const msgType = Object.prototype.toString.call(msg).toString()
        p.innerHTML += `<br/><p style="width: 100%;background-color: #bbff8f1a;border-radius: 10px;padding: 10px 10px;box-sizing: border-box;font-size:12px"><span style="font-size:13px;color:#69ff83;font-weight: 700">Dir列表<br />参数类型：${msgType.substring(
          7,
          msgType.length - 1
        )}<br /></span>${objOpen}</p>`
        p.scrollTop = p.scrollHeight
      }
      console.error = function (msg) {
        const errInfo = getStackTrace()
        if (/^\[Vue warn\]/.test(msg)) {
          //在自定义头部
          let typeText = '[ <span style="color:#42b883;font-weight: 700;">Vue 异常警告</span> ]:<br>'
          //截取说明
          let describe = ''
          let website = ""
          if (msg.indexOf('See:') === -1) {
            describe = msg.substring(msg.indexOf(': ') + 2, msg.indexOf('found in'))
          } else {
            describe = msg.substring(msg.indexOf(': ') + 2, msg.indexOf('See:'))
            //截取网址
            website = msg.substring(msg.indexOf('See:') + 4, msg.indexOf('found in'))
          }
          let tempDescribe = Str.replace(describe, '"', "'")
          if (/^Error in created hook/.test(describe)) {
            describe = describe.substring(describe.indexOf(': "') + 3, describe.lastIndexOf('"'))
            describe = getErrText(describe.substring(0, describe.indexOf(":"))) + describe.substring(describe.indexOf(': '), describe.length);
          } else if (/^Error in render/.test(describe)) {
            describe = describe.substring(describe.indexOf(': "') + 3, describe.lastIndexOf('"'))
            describe = getErrText(describe.substring(0, describe.indexOf(":"))) + describe.substring(describe.indexOf(': '), describe.length);
          } else {
            describe = Str.replace(describe, ".", ".<br>")
          }
          //截取错误位置
          let position = msg.substring(msg.indexOf('found in') + 8, msg.length)
          if (position.indexOf("--->") !== -1) {
            position = Str.replace(position, "--->", "<span style='color:#ffffff63'>来自于：</span>")
          }
          if (position.indexOf("at") !== -1) {
            position = Str.replace(position, "at ", "<br>")
          }
          msg = `${typeText}<br><span style="color:#42b883;font-weight: 700;">异常描述：</span>${Str.removeAllSpace(tempDescribe)!==""?`<a target="_blank" href="https://fanyi.baidu.com/#en/zh/${tempDescribe}" style="color:#f189ff;font-weight: 400;">点击翻译</a>`:""}<br>${describe}<br>${website?`<span style="color:#42b883;font-weight: 700;">参考网址：</span><br>`+`<a target="_blank" href=${website} style="color:#56c2ff;curser:'pointer'">${website}</a>`+"<br>":""}<br><span style="color:#42b883;font-weight: 700;">异常文件：</span><br>${position}`
        } else { 
        }
        p.innerHTML += `<br/><p style="
        width: 100%;
        background-color: #330000ab;
        border-radius: 10px;
        padding: 10px 10px;
        box-sizing: border-box;
        color:#ff4343">${msg}<p style="color:#78dce0;width:100%;text-align:right;">来自${errInfo[0]}文件 第${errInfo[1]}行</p></p>`
        p.scrollTop = p.scrollHeight
      }
      console.warn = function (msg) {
        const warnInfo = getStackTrace()
        p.innerHTML += `<br/><p style="
        width: 100%;
        background-color: #a08a00ab;
        border-radius: 10px;
        padding: 10px 10px;
        box-sizing: border-box;
        color:yellow">${msg}<p style="color:#78dce0;width:100%;text-align:right;">来自${warnInfo[0]}文件 第${warnInfo[1]}行</p></p>`
        p.scrollTop = p.scrollHeight
      }
      console.info = function (msg) {
        p.innerHTML += `<br/><p style="
        width: 100%;
        background-color: #73a6ffab;
        border-radius: 10px;
        padding: 10px 10px;
        box-sizing: border-box;
        color:#00128a">${msg}</p>`
        p.scrollTop = p.scrollHeight
      }
      console.debug = function (msg) {
        p.innerHTML += `<br/><p style="
        width: 100%;
        background-color: #d6e7ff08;
        border-radius: 10px;
        padding: 10px 10px;
        box-sizing: border-box;
        color:#0021ff">${msg}</p>`
        p.scrollTop = p.scrollHeight
      }
      Promise.reject = function (msg) {
        let errStr = `
        <p style="margin:10px;width: 100%;background-color: #5500008f;border-radius: 10px;padding: 10px 10px;box-sizing: border-box;color:#ff8184">
        <span style="display:block;width:100%;text-align:center;font-weight: 700;">${msg.name}</span><br/>`
        if (msg.config.method) {
          errStr += `请求方式：${msg.config.method}<br/><br/>`
        }
        if (msg.request.status) {
          const status = msg.request.status
          errStr += `状态码：${status} (${msg.request.statusText})<br/><br/>`
          switch (status) {
            case 206:
              errStr +=
                '<span style="color:yellow">可能原因：服务器已处理部分请求</span><br/><br/>'
              break
            case 301:
              errStr +=
                '<span style="color:yellow">可能原因：请求的网页已永久移动到新位置，请求的资源路径已经改变,可能响应头中的Location字段有新URL</span><br/><br/>'
              break
            case 302:
              errStr +=
                '<span style="color:yellow">可能原因：临时重定向，您或许该从不同地址进行请求，可能响应头中的Location字段有新URL</span><br/><br/>'
              break
            case 400:
              errStr +=
                '<span style="color:yellow">可能原因：错误请求，服务器无法理解该请求，请首先检查请求的字段名与字段值</span><br/><br/>'
              break
            case 401:
              errStr +=
                '<span style="color:yellow">可能原因：身份验证未通过</span><br/><br/>'
              break
            case 403:
              errStr +=
                '<span style="color:yellow">可能原因：服务器拒绝请求，可能为客户端错误</span><br/><br/>'
              break
            case 404:
              errStr +=
                '<span style="color:yellow">可能原因：链接失效，或者是URL拼写错误，亦或是Web服务器将所请求的资源移到了其它的地方</span><br/><br/>'
              break
            case 408:
              errStr +=
                '<span style="color:yellow">可能原因：等候请求时发生超时</span><br/><br/>'
              break
            case 500:
              errStr +=
                '<span style="color:yellow">可能原因：内部服务器错误，请首先检查请求方式、代码拼接或服务器配置</span><br/><br/>'
              break
            case 502:
              errStr +=
                '<span style="color:yellow">可能原因：错误网关</span><br/><br/>'
              break
            case 503:
              errStr +=
                '<span style="color:yellow">可能原因：服务器目前暂时无法使用</span><br/><br/>'
              break
          }
        }
        if (msg.request.responseURL) {
          errStr += `请求地址：<span style="color:#5c94ff">${msg.request.responseURL}</span><br/><br/>`
        }
        if (msg.config.data) {
          errStr += `请求负载(JSON格式)：<span style="color:#d38eff">${msg.config.data}</span><br/><br/>`
        }
        if (msg.config.headers) {
          const heard = msg.config.headers
          errStr += '请求头：<span style="color:#5ce2ff"><br/>'
          for (const key in heard) {
            errStr += `${key}: ${heard[key]}<br/>`
          }
          errStr += '</span>'
        }
        errStr += '</p>'
        p.innerHTML += errStr
      }
      window.onerror = function (errorMsg, url, lineNumber, column) {
        if (errorMsg.indexOf(':') !== -1) {
          errMsg.innerHTML =
            errorMsg.substring(errorMsg.indexOf(':') + 1) +
            "<br/><span style='color:#bff5bb;font-weight:400;font-size:12px'>[点击百度]</span>"
          errMsg.href = `https://www.baidu.com/s?wd=${errorMsg}`
          errMsg.target = '_blank'
          const type = errorMsg.substring(0, errorMsg.indexOf(':'))
          errType.innerText = type
          if (type.indexOf('SyntaxError') !== -1) {
            errType.innerText += '\n(语法错误)'
          } else if (type.indexOf('TypeError') !== -1) {
            errType.innerText += '\n(类型错误)'
          } else if (type.indexOf('ReferenceError') !== -1) {
            errType.innerText += '\n(引用错误)'
          } else if (type.indexOf('RangeError') !== -1) {
            errType.innerText += '\n(范围错误)'
          } else if (type.indexOf('URIError') !== -1) {
            errType.innerText += '\n(URI错误)'
          } else if (type.indexOf('EvalError') !== -1) {
            errType.innerText += '\n(Eval错误)'
          } else if (type.indexOf('InternalError') !== -1) {
            errType.innerText += '\n(内部错误)'
          } else errType.innerText += '\n(未定义类型的错误)'
        } else {
          errMsg.innerHTML = errorMsg.substring(
            errorMsg.indexOf(' ') + 1
          )
          errMsg.href = `https://www.baidu.com/s?wd=${errorMsg}`
          errMsg.target = '_blank'
          const type = errorMsg.substring(0, errorMsg.indexOf(' '))
          errType.innerText = type
          if (/^Uncaught/.test(type)) {
            errType.innerText += '\n(未定义类型的错误)'
          }
        }
        errFromA.href = `${url}`
        errFromA.innerText =
          url.substring(url.lastIndexOf('/') + 1) +
          `:${lineNumber}:${column}`
        errFromA.target = '_blank'
        errLine.innerText = `\n[ 第 ${lineNumber} 行 - 第 ${column} 字 ]`
        p.prepend(errDiv)
        p.scrollTop = p.scrollHeight
      }
      if (msg) p.innerHTML += `<br/>${msg}`
    } else {
      dq('.__YHBToolLogFloatText').innerHTML += `<br/>${msg}`
      dq('.__YHBToolLogFloatText').scrollTop = dq(
        '.__YHBToolLogFloatText'
      ).scrollHeight
    }
  }
}
/**
 * 秒数格式化，根据输入秒数，转化为年月日时分秒格式，如果某一项为零则不打印
 * @param {秒数} second Number
 * @param {年月日分隔符} separatorYMD String
 * @param {日与时的分隔符} separatorDH String
 * @param {时分秒分隔符} separatorHMS String
 * @returns String
 */
function formatSecond (
  second = 0,
  separatorYMD = '/',
  separatorDH = ' ',
  separatorHMS = ':'
) {
  let formatStr = ''
  const Y = parseInt(second / 60 / 60 / 24 / 365)
  const M = parseInt(second / 60 / 60 / 24 / 30.5) % 12
  const D = parseInt(second / 60 / 60 / 24) % 30.5
  const h = parseInt(second / 60 / 60) % 24
  const m = parseInt(second / 60) % 60
  const s = parseInt(second % 60)
  Y && (formatStr += Y + '年' + separatorYMD)
  M && (formatStr += (M < 10 ? '0' + M : M) + '月' + separatorYMD)
  D && (formatStr += (D < 10 ? '0' + D : D) + '日' + separatorDH)
  h && (formatStr += (h < 10 ? '0' + h : h) + '时' + separatorHMS)
  m && (formatStr += (m < 10 ? '0' + m : m) + '分' + separatorHMS)
  formatStr += (s < 10 ? '0' + s : s) + '秒'
  return formatStr
}

let __YHBToolDigitResult = 0
let __YHBToolDigitResultArr = [0]
/**
 * 数字处理
 */
const Digit = {
  /**
   * 精确15位的圆周率（js最大精度）
   * 精确70位的圆周率（字符串）
   */
  PI: 3.141592653589793,
  StringPI:
    '3.1415926535897932384626433832795028841971693993751058209741445923078164',
  /**
   * 精确15位的自然对数e（js最大精度）
   * 精确70位的自然对数e（字符串）
   */
  E: 2.718281828459045,
  StringE:
    '2.7182818284590452353602874713526624977572470936999595749669676277240766',
  /**
   * 精确15位的黄金分割数Ф（js最大精度）
   * 精确70位的黄金分割数Ф（字符串）
   */
  FI: 0.618033988749894,
  StringFI:
    '0.6180339887498948482045868343656381177203091798057628621354486227052604',
  /**
   * 将数组内容求和
   * @param {需要求和的数组} numArr NumberArray
   * @returns Number
   */
  sum: function (numArr = []) {
    if (!numArr.length) return NaN
    __YHBToolDigitResult = 0
    for (let i = 0; i < numArr.length; i++) {
      if (!Number(numArr[i])) return NaN
      __YHBToolDigitResult += numArr[i]
    }
    return __YHBToolDigitResult
  },
  /**
   * 输出数组中的最小值
   * @param {需要求最小值的数组} numArr NumberArray
   * @returns Number
   */
  min: function (numArr = []) {
    if (!numArr.length) return NaN
    __YHBToolDigitResult = numArr[0]
    for (let i = 0; i < numArr.length; i++) {
      if (!Number(numArr[i])) return NaN
      if (numArr[i] < __YHBToolDigitResult) {
        __YHBToolDigitResult = numArr[i]
      }
    }
    return __YHBToolDigitResult
  },
  /**
   * 输出数组中的最大值
   * @param {需要求最大值的数组} numArr NumberArray
   * @returns Number
   */
  max: function (numArr = []) {
    if (!numArr.length) return NaN
    __YHBToolDigitResult = numArr[0]
    for (let i = 0; i < numArr.length; i++) {
      if (!Number(numArr[i])) return NaN
      if (numArr[i] > __YHBToolDigitResult) {
        __YHBToolDigitResult = numArr[i]
      }
    }
    return __YHBToolDigitResult
  },
  /**
   * 返回数组中的全部奇数
   * @param {需要求全部奇数的数组} numArr NumberArray
   * @returns NumberArray
   */
  odd: function (numArr = []) {
    if (!numArr.length) return NaN
    __YHBToolDigitResultArr = []
    for (let i = 0; i < numArr.length; i++) {
      if (!Number(numArr[i])) return NaN
      if (numArr[i] % 2) __YHBToolDigitResultArr.push(numArr[i])
    }
    return __YHBToolDigitResultArr
  },
  /**
   * 返回数组中的全部偶数
   * @param {需要求全部偶数的数组} numArr NumberArray
   * @returns NumberArray
   */
  even: function (numArr = []) {
    if (!numArr.length) return NaN
    __YHBToolDigitResultArr = []
    for (let i = 0; i < numArr.length; i++) {
      if (!Number(numArr[i])) return NaN
      if (!(numArr[i] % 2)) __YHBToolDigitResultArr.push(numArr[i])
    }
    return __YHBToolDigitResultArr
  },
  /**
   * 返回数组中全部大于than的数
   * @param {需求数组} numArr NumberArray
   * @param {大于某数} than Number
   * @returns NumberArray
   */
  greater: function (numArr = [], than = 0) {
    if (!numArr.length) return NaN
    __YHBToolDigitResultArr = []
    for (let i = 0; i < numArr.length; i++) {
      if (!Number(numArr[i])) return NaN
      if (!(numArr[i] > than)) {
        __YHBToolDigitResultArr.push(numArr[i])
      }
    }
    return __YHBToolDigitResultArr
  },
  /**
   * 返回数组中全部小于than的数
   * @param {需求数组} numArr NumberArray
   * @param {小于某数} than Number
   * @returns NumberArray
   */
  less: function (numArr = [], than = 0) {
    if (!numArr.length) return NaN
    __YHBToolDigitResultArr = []
    for (let i = 0; i < numArr.length; i++) {
      if (!Number(numArr[i])) return NaN
      if (!(numArr[i] < than)) {
        __YHBToolDigitResultArr.push(numArr[i])
      }
    }
    return __YHBToolDigitResultArr
  },
  /**
   * 返回数组中能被divisor整除的所有数
   * @param {需要求能被某个数整除的数组} numArr NumberArray
   * @param {其他数能被此数整除} divisor Number
   * @returns NumberArray
   */
  aliquot: function (numArr = [], divisor) {
    if (!numArr.length) return NaN
    __YHBToolDigitResultArr = []
    for (let i = 0; i < numArr.length; i++) {
      if (!Number(numArr[i])) return NaN
      if (!(numArr[i] % divisor)) {
        __YHBToolDigitResultArr.push(numArr[i])
      }
    }
    return __YHBToolDigitResultArr
  },
  /**
   * 返回数组中的全部质数
   * @param {需要求全部质数的数组} numArr NumberArray
   * @returns NumberArray
   */
  prime: function (numArr = []) {
    if (!numArr.length) return NaN
    __YHBToolDigitResultArr = []
    let isPrime = true
    for (let i = 0; i < numArr.length; i++) {
      if (!Number(numArr[i])) return NaN
      for (let j = 2; j < numArr[i] && isPrime; j++) {
        if (!(numArr[i] % j)) isPrime = false
      }
      if (isPrime) __YHBToolDigitResultArr.push(numArr[i])
      isPrime = true
    }
    return __YHBToolDigitResultArr
  },
  /**
   * 返回数组中的全部合数
   * @param {需要求全部合数的数组} numArr NumberArray
   * @returns NumberArray
   */
  composite: function (numArr = []) {
    if (!numArr.length) return NaN
    __YHBToolDigitResultArr = []
    let isComposite = false
    for (let i = 0; i < numArr.length; i++) {
      if (!Number(numArr[i])) return NaN
      for (let j = 2; j < numArr[i] && !isComposite; j++) {
        if (!(numArr[i] % j)) isComposite = true
      }
      if (isComposite) __YHBToolDigitResultArr.push(numArr[i])
      isComposite = false
    }
    return __YHBToolDigitResultArr
  },
  /**
   * 升序排列数组
   * @param {需要被升序排列的数组} numArr NumberArray
   * @returns NumberArray
   */
  ascending: function (numArr = []) {
    if (!numArr.length) return NaN
    __YHBToolDigitResultArr = numArr
    for (let i = 0; i < __YHBToolDigitResultArr.length; i++) {
      // if(!Number(numArr[i]))return NaN
      for (let j = 0; j < __YHBToolDigitResultArr.length - i; j++) {
        if (j + 1 < __YHBToolDigitResultArr.length) {
          if (
            __YHBToolDigitResultArr[j] >
            __YHBToolDigitResultArr[j + 1]
          ) {
            const temp = __YHBToolDigitResultArr[j + 1]
            __YHBToolDigitResultArr[j + 1] =
              __YHBToolDigitResultArr[j]
            __YHBToolDigitResultArr[j] = temp
          }
        }
      }
    }
    return __YHBToolDigitResultArr
  },
  /**
   * 降序排列数组
   * @param {需要被降序排列的数组} numArr NumberArray
   * @returns NumberArray
   */
  descending: function (numArr = []) {
    if (!numArr.length) return NaN
    __YHBToolDigitResultArr = numArr
    for (let i = 0; i < __YHBToolDigitResultArr.length; i++) {
      if (!Number(numArr[i])) return NaN
      for (let j = 0; j < __YHBToolDigitResultArr.length - i; j++) {
        if (j + 1 < __YHBToolDigitResultArr.length) {
          if (
            __YHBToolDigitResultArr[j] <
            __YHBToolDigitResultArr[j + 1]
          ) {
            const temp = __YHBToolDigitResultArr[j + 1]
            __YHBToolDigitResultArr[j + 1] =
              __YHBToolDigitResultArr[j]
            __YHBToolDigitResultArr[j] = temp
          }
        }
      }
    }
    return __YHBToolDigitResultArr
  },
  /**
   * 保留指定小数位数(直接保留)
   * @param {需要保留小数位数的数字} num Float
   * @param {保留位数} place Number
   * @returns Float
   */
  Place: function (num = 0.0, place = 2) {
    const temp = Math.pow(10, place)
    return parseInt(num * temp) / temp
  },
  /**
   * 保留指定小数位数(四舍五入)
   * @param {需要保留小数位数的数字} num Float
   * @param {四舍五入保留位数} place Number
   * @returns Float
   */
  PlaceRounded: function (num = 0.0, place = 2) {
    return +parseFloat(num + 0).toFixed(place)
  },
  /**
   * 整数随机数
   * @param {随机整数的最小值} min Number
   * @param {随机整数的最大值} max Number
   * @param {是否需要包含最大值} closed Boolean
   * @returns Number
   */
  randomInt: function (min = 0, max = 10, closed = false) {
    return closed
      ? parseInt(Math.random() * (max - min + 1) + min)
      : parseInt(Math.random() * (max - min) + min)
  },
  /**
   * 小数随机数
   * @param {随机数的最小值} min Number
   * @param {随机数的最大值} max Number
   * @param {是否需要包含最大值} closed Boolean
   * @returns Float
   */
  randomFloat: function (min = 0, max = 10, closed = false) {
    return closed
      ? Math.random() * (max - min + 1) + min
      : Math.random() * (max - min) + min
  },
  /**
   * 将0-10的数字转换为中文，可设置是否繁体
   * @param {数字} num
   * @param {繁体} Traditional
   * @returns String|NaN
   */
  toCN: function (num, Traditional = false) {
    if (!Number(num)) return NaN
    switch (num) {
      case 0:
        return '零'
      case 1:
        return Traditional ? '壹' : '一'
      case 2:
        return Traditional ? '贰' : '二'
      case 3:
        return Traditional ? '叁' : '三'
      case 4:
        return Traditional ? '肆' : '四'
      case 5:
        return Traditional ? '伍' : '五'
      case 6:
        return Traditional ? '陆' : '六'
      case 7:
        return Traditional ? '柒' : '七'
      case 8:
        return Traditional ? '捌' : '八'
      case 9:
        return Traditional ? '玖' : '九'
      case 10:
        return Traditional ? '拾' : '十'
      default:
        return NaN
    }
  },
  /**
   * 将数组中的数据求平均值
   * @param {求平均值的数组} numArr
   * @returns Number
   */
  average: function (numArr = []) {
    if (!numArr.length) return NaN
    __YHBToolDigitResultArr = numArr
    const age =
      __YHBToolDigitResultArr.reduce((sum, item) => {
        return sum + item
      }, 0) / __YHBToolDigitResultArr.length
    return age
  }
}

const __YHBToolStrResultStrArr = []
/**
 * 字符串处理类
 */
const Str = {
  /**
   * 按照顺序分离字符串中的数字、字母与其他字符
   * @param {需要处理的字符串} str String
   * @returns Array
   */
  subArr: function (str = '') {
    let strTemp = ''
    let numTemp = ''
    let otherTemp = ''
    for (let i = 0; i < str.length; i++) {
      const temp = str.substring(i, i + 1)
      if (temp !== ' ') {
        if (temp !== 0) {
          if (Number(temp)) {
            numTemp += temp
            strTemp && __YHBToolStrResultStrArr.push(strTemp)
            if (otherTemp) __YHBToolStrResultStrArr.push(otherTemp)
            else {
              strTemp = ''
              otherTemp = ''
            }
          } else if (/^[A-Za-z]+$/.test(temp)) {
            strTemp += temp
            numTemp && __YHBToolStrResultStrArr.push(+numTemp)
            if (otherTemp) __YHBToolStrResultStrArr.push(otherTemp)
            else {
              numTemp = ''
              otherTemp = ''
            }
          } else {
            otherTemp += temp
            numTemp && __YHBToolStrResultStrArr.push(+numTemp)
            if (strTemp) __YHBToolStrResultStrArr.push(strTemp)
            else {
              numTemp = ''
              strTemp = ''
            }
          }
        } else {
          numTemp += temp
          strTemp && __YHBToolStrResultStrArr.push(strTemp)
          if (otherTemp) __YHBToolStrResultStrArr.push(otherTemp)
          else {
            strTemp = ''
            otherTemp = ''
          }
        }
      }
    }
    strTemp && __YHBToolStrResultStrArr.push(strTemp)
    numTemp && __YHBToolStrResultStrArr.push(+numTemp)
    otherTemp && __YHBToolStrResultStrArr.push(otherTemp)
    return __YHBToolStrResultStrArr
  },

  /**
   * 去除字符串首尾空格
   * @param {需要处理的字符串} str String
   * @returns String
   */
  removeSpace: function (str = '') {
    if (str.substring(0, 1) === ' ') {
      str = str.substring(1, str.length)
    }
    if (str.substring(str.length - 1, str.length) === ' ') {
      str = str.substring(0, str.length - 1)
    }
    return str
  },

  /**
   * 去除字符串中的全部空格
   * @param {需要处理的字符串} str String
   * @returns String
   */
  removeAllSpace: function (str = '') {
    return str
      .split('')
      .map(item => {
        if (item !== ' ') return item
        else return item
      })
      .join('')
  },

  /**
   * 将字符串中的字符每num个为一组，储存为数组，不足字数的直接储存
   * @param {需要处理的字符串} str String
   * @param {分段字数} num Number
   * @returns Array
   */
  section: function (str = '', num = 1) {
    if (str.length <= num || !num || typeof num !== 'number') {
      return Array(str)
    }
    const tempArr = []
    while (true) {
      tempArr.push(str.substring(0, num))
      str = str.substring(num, str.length)
      if (str.length <= num) {
        tempArr.push(str)
        break
      }
    }
    return tempArr
  },

  /**
   * 将字符串按照指定字符分割成数组
   * @param {需要处理的字符串} str
   * @param {分割字符} char
   * @returns Array
   */
  subChar: function (str = '', char = '') {
    if (typeof str !== 'string' || str.indexOf(char) === -1) {
      return Array(str)
    }
    str = str.split('')
    let temp = ''
    const tempArr = []
    for (let i = 0; i < str.length; i++) {
      if (str[i] !== char) {
        temp += str[i]
      } else {
        if (temp) tempArr.push(temp)
        temp = ''
      }
    }
    if (temp) tempArr.push(temp)
    return tempArr
  },
  /**
   * 将字符串中的每个targetStr都替换成replaceStr
   * @param {需要处理的字符串} str String
   * @param {目标字符} targetStr String
   * @param {替换字符} replaceStr String
   * @returns String
   */
  replace: function (str = '', targetStr = '', replaceStr = '') {
    if (typeof str !== 'string' || str.indexOf(targetStr) === -1) {
      return Array(str)
    }
    const temp = []
    for (let i = 0; i < str.length; i++) {
      const char = str.substring(i, i + 1)
      if (char === targetStr) temp.push(replaceStr)
      else temp.push(char)
    }
    return temp.join('')
  }
}
/**
 * 字符类
 */
const Char = {
  /**
   * 是否为小写字母
   * @param {字符} char
   * @returns Boolean
   */
  isLowercase: function (char = '') {
    if (!char || !Is.String(char) || char.length !== 1) {
      console.error(char + '不是字符')
      return undefined
    }
    return /^[a-z]$/.test(char)
  },
  /**
   * 是否为大写字母
   * @param {字符} char
   * @returns Boolean
   */
  isUppercase: function (char = '') {
    if (!char || !Is.String(char) || char.length !== 1) {
      console.error(char + '不是字符')
      return undefined
    }
    return /^[A-Z]$/.test(char)
  }
}

/**
 *  颜色转换类
 */
const Color = {
  /**
   * 将RGB转换为16进制 不加#号
   * @param {红色数值或者rgb格式字符串} RRgb Number||String
   * @param {绿色数值} G Number
   * @param {蓝色数值} B Number
   * @returns String
   */
  toHex: function (RRgb = 0, G = 0, B = 0) {
    if (
      (RRgb + '').substring(0, 4).toLowerCase() === 'rgb(' ||
      (RRgb + '').substring(0, 1).toLowerCase() === '('
    ) {
      const rgbArr = RRgb.split(',')
      RRgb = parseInt(rgbArr[0].split('(')[1])
      G = parseInt(rgbArr[1])
      B = parseInt(rgbArr[2].split(')')[0])
    }
    if (
      RRgb > 255 ||
      RRgb < 0 ||
      G > 255 ||
      G < 0 ||
      B > 255 ||
      B < 0 ||
      RRgb === undefined ||
      G === undefined ||
      B === undefined
    ) {
      return undefined
    }
    let hex = ''
    getHex(RRgb)
    getHex(G)
    getHex(B)
    return hex
    function getHex (C) {
      switchHex(parseInt(C / 16))
      switchHex(C % 16)
      function switchHex (num) {
        switch (num) {
          case 10:
            hex += 'A'
            break
          case 11:
            hex += 'B'
            break
          case 12:
            hex += 'C'
            break
          case 13:
            hex += 'D'
            break
          case 14:
            hex += 'E'
            break
          case 15:
            hex += 'F'
            break
          default:
            hex += num
        }
      }
    }
  },
  toRGB: function (Hex) {}
}

/**
 * 计时器相关方法
 */
const Timer = {
  /**
   * 将给定元素的内容变成倒计时
   * @param {需要用来显示的元素} element String
   * @param {倒计时的开始时间} start Number
   * @param {倒计时的结束时间_一般不修改} end Number
   */
  countdown: function (element, start = 10, end = 0) {
    const ele = existElement(element, '元素不存在(Timer.countdown)')
    if (!ele[0]) return
    element = ele[1]
    const time = setInterval(function () {
      start < end
        ? (element.innerHTML = start--)
        : clearInterval(time)
    }, 1000)
  },
  /**
   * 将给定元素的内容变成正向计时
   * @param {需要用来显示的元素} element String
   * @param {计时的结束时间} end Number
   * @param {计时的开始时间_一般不修改} start Number
   */
  timing: function (element, end = 10, start = 0) {
    const ele = existElement(element, '元素不存在(Timer.timing)')
    if (!ele[0]) return
    element = ele[1]
    const time = setInterval(function () {
      start <= end
        ? (element.innerHTML = start++)
        : clearInterval(time)
    }, 1000)
  },
  /**
   * 将数组的内容依次刷新显示
   * @param {需要用来显示的元素} element String
   * @param {顺序依次显示的数组} arr Array
   * @param {间隔时间} interval Number
   * @param {是否一直从头循环} cycle Boolean
   */
  shuffling: function (
    element,
    arr = [],
    interval = 1000,
    cycle = false
  ) {
    const ele = existElement(element, '元素不存在(Timer.shuffling)')
    if (!ele[0]) return
    element = ele[1]
    let index = 0
    const time = setInterval(function () {
      index < arr.length
        ? (element.innerHTML = arr[index++])
        : cycle
          ? (index = 0)
          : clearInterval(time)
    }, interval)
  },
  /**
   * 循环轮播图
   * @param {需要用来更换图片的img标签元素_CSS选择器} imgElement String
   * @param {顺序依次显示的图片路径数组} arrURL Array
   * @param {间隔时间} interval Number
   */
  shufflingIMG: function (imgElement, arrURL = [], interval = 1000) {
    const ele = existElement(
      imgElement,
      '元素不存在(Timer.shufflingIMG)'
    )
    if (!ele[0]) return
    imgElement = ele[1]
    let index = 0
    setInterval(function () {
      imgElement.src = arrURL[index]
      ++index === arrURL.length && (index = 0)
    }, interval)
  },
  /**
   * 循环轮播图、进度点
   * @param {需要用来更换图片的img标签元素_CSS选择器} imgElement String
   * @param {需要用来显示轮换进度的同名兄弟标签元素_CSS选择器} pointElement String
   * @param {需要用来轮换的同名兄弟标签元素的样式类名} pointActiveClassName String
   * @param {顺序依次显示的图片路径数组} arrURL Array
   * @param {间隔时间} interval Number
   */
  shufflingIMGPoint: function (
    imgElement,
    pointElement,
    pointActiveClassName,
    arrURL = [],
    interval = 1000
  ) {
    const ele = existElement(
      imgElement,
      '元素不存在(Timer.shufflingIMGPoint)'
    )
    if (!ele[0]) return
    imgElement = ele[1]
    let index = 0
    if (pointActiveClassName.substring(0, 1) === '.') {
      pointActiveClassName = pointActiveClassName.substring(
        1,
        pointActiveClassName.length
      )
    }
    setInterval(function () {
      imgElement.src = arrURL[index]
      document
        .querySelector('.' + pointActiveClassName)
        .classList.remove(pointActiveClassName)
      document
        .querySelector(pointElement + `:nth-child(${index + 1})`)
        .classList.toggle(pointActiveClassName)
      ++index === arrURL.length && (index = 0)
    }, interval)
  },
  /**
   * 循环轮播图、进度点、前后切换按钮
   * @param {轮播图全组件的父元素_CSS选择器} superiorElement String
   * @param {需要用来更换图片的img标签元素_CSS选择器} imgElement String
   * @param {需要用来显示轮换进度的同名兄弟标签元素_CSS选择器} pointElement String
   * @param {需要用来轮换的同名兄弟标签元素的样式类名} pointActiveClassName String
   * @param {显示上一张的按钮或点击元素_CSS选择器} prevBtn String
   * @param {显示下一张的按钮或点击元素_CSS选择器} nextBtn String
   * @param {顺序依次显示的图片路径数组} arrURL Array
   * @param {间隔时间} time Number
   */
  shufflingIMGPointBtn: function (
    superiorElement,
    imgElement,
    pointElement,
    pointActiveClassName,
    prevBtn,
    nextBtn,
    arrURL = [],
    time = 1000
  ) {
    let ele = existElement(
      superiorElement,
      '元素不存在(Timer.shufflingIMGPointBtn)'
    )
    if (!ele[0]) return
    superiorElement = ele[1]
    ele = existElement(
      imgElement,
      '元素不存在(Timer.shufflingIMGPointBtn)'
    )
    if (!ele[0]) return
    imgElement = ele[1]
    let index = 0
    let SetInterval = 0
    if (pointActiveClassName.substring(0, 1) === '.') {
      pointActiveClassName = pointActiveClassName.substring(
        1,
        pointActiveClassName.length
      )
    }
    Interval()
    function Interval () {
      SetInterval = setInterval(function () {
        ++index === arrURL.length && (index = 0)
        play()
      }, time)
    }
    superiorElement.addEventListener('mouseenter', function () {
      clearInterval(SetInterval)
    })
    superiorElement.addEventListener('mouseleave', function () {
      Interval()
    })
    dq(prevBtn).addEventListener('click', function () {
      --index < 0 && (index = arrURL.length - 1)
      play()
    })
    dq(nextBtn).addEventListener('click', function () {
      ++index >= arrURL.length && (index = 0)
      play()
    })

    function play () {
      imgElement.src = arrURL[index]
      document
        .querySelector('.' + pointActiveClassName)
        .classList.remove(pointActiveClassName)
      document
        .querySelector(pointElement + `:nth-child(${index + 1})`)
        .classList.add(pointActiveClassName)
    }
  }
}

/**
 * 时间类
 */
const FormatDate = {
  /**
   * 根据传入的时间对象或者时间字符串，对其进行格式化
   * 格式化的格式为formatStr，支持年月日时分秒、以及小时制的切换
   * @param {日期或日期字符串} date 
   * @param {日期格式} formatStr 
   * @returns String
   */
  format(date,formatStr) {
    if (formatStr === undefined || formatStr === null || formatStr === "") {
      if (date === undefined || date === null || date === "") { return undefined }
      else {
        formatStr = "YYYY-MM-DD HH:mm:ss"
        return formatDate()
      }
    } else { 
      if (!Is.Date(date)) { date = new Date(date.replace(/-/g, '/')) }
      return formatDate()
    }
    function formatDate() {
      let Y_M = ""
      let M_D = ""
      let D_h = ""
      let h_m = ""
      let m_s = ""
      let YStr = ""
      let MStr = ""
      let DStr = ""
      let hStr = ""
      let mStr = ""
      let sStr = ""
      let isHour12 = false
      if (formatStr.indexOf("YYYY") !== -1) {
        YStr = date.getFullYear().toString()
        Y_M = formatStr.substring(4,5)
      }
      else if (formatStr.indexOf("YYY") !== -1) {
        YStr = date.getFullYear().toString()
        YStr = YStr.substring(YStr.length-3,YStr.length)
        Y_M = formatStr.substring(3,4)
      }
      else if (formatStr.indexOf("YY") !== -1) {
        YStr = date.getFullYear().toString()
        YStr = YStr.substring(YStr.length-2,YStr.length)
        Y_M = formatStr.substring(2,3)
      }
      if (formatStr.indexOf("MM") !== -1) {
        MStr = (date.getMonth() + 1).toString()
        MStr = MStr.length < 2 ? '0' + MStr : MStr
        M_D = formatStr.substring(formatStr.indexOf("MM")+2,formatStr.indexOf("MM")+3)
      }
      else if (formatStr.indexOf("M") !== -1) {
        MStr = date.getMonth() + 1
        M_D = formatStr.substring(formatStr.indexOf("M")+1,formatStr.indexOf("M")+2)
      }
      if (formatStr.indexOf("DD") !== -1) {
        DStr = date.getDate().toString()
        DStr = DStr.length < 2 ? '0' + DStr : DStr
        D_h = formatStr.substring(formatStr.indexOf("DD")+2,formatStr.indexOf("DD")+3)
      }
      else if (formatStr.indexOf("D") !== -1) {
        DStr = date.getDate()
        D_h = formatStr.substring(formatStr.indexOf("D")+1,formatStr.indexOf("D")+2)
      }
      if (formatStr.indexOf("HH") !== -1) {
        hStr = date.getHours().toString()
        hStr = hStr.length < 2 ? '0' + hStr : hStr
        h_m = formatStr.substring(formatStr.indexOf("HH")+2,formatStr.indexOf("HH")+3)
      }
      else if (formatStr.indexOf("H") !== -1) { 
        hStr = date.getHours()
        h_m = formatStr.substring(formatStr.indexOf("H")+1,formatStr.indexOf("H")+2)
      }
      else if (formatStr.indexOf("hh") !== -1) {
        hStr = date.getHours()
        switch (hStr) { 
          case 13:
            hStr = 1
            break;
          case 14:
            hStr = 2
            break;
          case 15:
            hStr = 3
            break;
          case 16:
            hStr = 4
            break;
          case 17:
            hStr = 5
            break;
          case 18:
            hStr = 6
            break;
          case 19:
            hStr = 7
            break;
          case 20:
            hStr = 8
            break;
          case 21:
            hStr = 9
            break;
          case 22:
            hStr = 10
            break;
          case 23:
            hStr = 11
            break;
        }
        hStr = hStr.toString()
        hStr = hStr.length < 2 ? '0' + hStr : hStr
        h_m = formatStr.substring(formatStr.indexOf("hh") + 2, formatStr.indexOf("hh") + 3)
        isHour12 = true
      }
      else if (formatStr.indexOf("h") !== -1) {
        hStr = date.getHours()
        switch (hStr) { 
          case 13:
            hStr = 1
            break;
          case 14:
            hStr = 2
            break;
          case 15:
            hStr = 3
            break;
          case 16:
            hStr = 4
            break;
          case 17:
            hStr = 5
            break;
          case 18:
            hStr = 6
            break;
          case 19:
            hStr = 7
            break;
          case 20:
            hStr = 8
            break;
          case 21:
            hStr = 9
            break;
          case 22:
            hStr = 10
            break;
          case 23:
            hStr = 11
            break;
        }
        h_m = formatStr.substring(formatStr.indexOf("h") + 1, formatStr.indexOf("h") + 2)
        isHour12 = true
      }
      if (formatStr.indexOf("mm") !== -1) {
        mStr = date.getMinutes().toString()
        mStr = mStr.length < 2 ? '0' + mStr : mStr
        m_s = formatStr.substring(formatStr.indexOf("mm")+2,formatStr.indexOf("mm")+3)
      }
      else if (formatStr.indexOf("m") !== -1) {
        mStr = date.getMinutes()
        m_s = formatStr.substring(formatStr.indexOf("m")+1,formatStr.indexOf("m")+2)
      }
      if (formatStr.indexOf("ss") !== -1) {
        sStr = date.getSeconds().toString()
        sStr = sStr.length < 2 ? '0' + sStr : sStr
      }
      else if (formatStr.indexOf("s") !== -1) {
        sStr = date.getSeconds()
      }
      let str = YStr + Y_M + MStr + M_D + DStr + D_h + hStr + h_m + mStr + m_s + sStr
      if (isHour12) {
        if (date.getHours() > 12) {
          str += " p. m."
        } else {
          str += " a. m."
        }
      }
      return str
    }
  },
  /**
   * 输入年份是否为闰年，默认为今年
   * @param {年份} year
   * @returns Boolean
   */
  isLeapYear: function (year = '') {
    if (year === '' || !Number(year)) year = new Date().getFullYear()
    return year % 400 === 0
  },
  /**
   * 获取本年的初始时间，可自定义分隔符的年月日时分秒
   * @param {是否需要返回时分秒} needHMS Boolean
   * @param {年月日的分隔符} SeparatorYMD string
   * @param {日与时之间的分隔符} SeparatorDH string
   * @param {时分秒的分隔符} SeparatorHMS string
   * @returns string
   */
  getInitial: function (
    needHMS = false,
    SeparatorYMD = '-',
    SeparatorDH = ' ',
    SeparatorHMS = ':'
  ) {
    const date = new Date()
    const YMDStr =
      date.getFullYear().toString() +
      SeparatorYMD +
      '01' +
      SeparatorYMD +
      '01'
    const HMSStr = '00' + SeparatorHMS + '00' + SeparatorHMS + '00'
    return needHMS ? YMDStr + SeparatorDH + HMSStr : YMDStr
  },
  /**
   * 获取本年的末尾时间，可自定义分隔符的年月日时分秒
   * @param {是否需要返回时分秒} needHMS Boolean
   * @param {年月日的分隔符} SeparatorYMD string
   * @param {日与时之间的分隔符} SeparatorDH string
   * @param {时分秒的分隔符} SeparatorHMS string
   * @returns string
   */
  getEnd: function (
    needHMS = false,
    SeparatorYMD = '-',
    SeparatorDH = ' ',
    SeparatorHMS = ':'
  ) {
    const date = new Date()
    const YMDStr =
      date.getFullYear().toString() +
      SeparatorYMD +
      '12' +
      SeparatorYMD +
      '31'
    const HMSStr = '23' + SeparatorHMS + '59' + SeparatorHMS + '59'
    return needHMS ? YMDStr + SeparatorDH + HMSStr : YMDStr
  },
  /**
   * 获取本周的初始时间，可自定义分隔符的月日时分秒
   * @param {是否需要返回时分秒} needHMS Boolean
   * @param {是否需要返回年} needY Boolean
   * @param {年月日的分隔符} SeparatorYMD string
   * @param {日与时之间的分隔符} SeparatorDH string
   * @param {时分秒的分隔符} SeparatorHMS string
   * @returns string
   */
  getWeekInitial: function (
    needHMS = false,
    needY = true,
    SeparatorYMD = '-',
    SeparatorDH = ' ',
    SeparatorHMS = ':'
  ) {
    let date = new Date()
    const YStr = date.getFullYear().toString()
    const weekStr = date.getDay()
    let num = weekStr - 1
    if (weekStr === 0) num = 6
    const Monday = Date.now() - num * 86400000
    date = new Date(Monday)
    let MDStr =
      format((date.getMonth() + 1).toString()) +
      SeparatorYMD +
      format(date.getDate().toString())
    const HMSStr = '00' + SeparatorHMS + '00' + SeparatorHMS + '00'
    function format (str) {
      return str.length < 2 ? '0' + str : str
    }
    needY && (MDStr = YStr + SeparatorYMD + MDStr)
    return needHMS ? MDStr + SeparatorDH + HMSStr : MDStr
  },
  /**
   * 获取本月的初始时间，可自定义分隔符的月日时分秒
   * @param {是否需要返回时分秒} needHMS Boolean
   * @param {是否需要返回年} needY Boolean
   * @param {年月日的分隔符} SeparatorYMD string
   * @param {日与时之间的分隔符} SeparatorDH string
   * @param {时分秒的分隔符} SeparatorHMS string
   * @returns string
   */
  getMonthInitial: function (
    needHMS = false,
    needY = true,
    SeparatorYMD = '-',
    SeparatorDH = ' ',
    SeparatorHMS = ':'
  ) {
    const date = new Date()
    const YStr = date.getFullYear().toString()
    let MDStr =
      format((date.getMonth() + 1).toString()) + SeparatorYMD + '01'
    const HMSStr = '00' + SeparatorHMS + '00' + SeparatorHMS + '00'
    function format (str) {
      return str.length < 2 ? '0' + str : str
    }
    needY && (MDStr = YStr + SeparatorYMD + MDStr)
    return needHMS ? MDStr + SeparatorDH + HMSStr : MDStr
  },
  /**
   * 获取本月的末尾时间，可自定义分隔符的月日时分秒
   * @param {是否需要返回时分秒} needHMS Boolean
   * @param {是否需要返回年} needY Boolean
   * @param {年月日的分隔符} SeparatorYMD string
   * @param {日与时之间的分隔符} SeparatorDH string
   * @param {时分秒的分隔符} SeparatorHMS string
   * @returns string
   */
  getMonthEnd: function (
    needHMS = false,
    needY = true,
    SeparatorYMD = '-',
    SeparatorDH = ' ',
    SeparatorHMS = ':'
  ) {
    const date = new Date()
    const YStr = date.getFullYear().toString()
    const month = format((date.getMonth() + 1).toString())
    let day = 31
    if (/^04|06|09|11$/.test(month)) {
      day = 30
    } else if (/^02$/.test(month)) {
      if (this.isLeapYear(date.getFullYear())) day = 29
      else day = 28
    }
    let MDStr = month + SeparatorYMD + day
    const HMSStr = '23' + SeparatorHMS + '59' + SeparatorHMS + '59'
    function format (str) {
      return str.length < 2 ? '0' + str : str
    }
    needY && (MDStr = YStr + SeparatorYMD + MDStr)
    return needHMS ? MDStr + SeparatorDH + HMSStr : MDStr
  },
  /**
   * 获取自定义分隔符的时分秒
   * @param {时分秒的分隔符} SeparatorHMS string
   * @returns string
   */
  getHMS: function (SeparatorHMS = ':') {
    const date = new Date()
    const Hours = format(date.getHours().toString())
    const Minutes = format(date.getMinutes().toString())
    const Seconds = format(date.getSeconds().toString())
    function format (str) {
      return str.length < 2 ? '0' + str : str
    }
    return Hours + SeparatorHMS + Minutes + SeparatorHMS + Seconds
  },
  /**
   * 获取自定义分隔符的年月日
   * @param {年月日的分隔符} SeparatorYMD string
   * @returns string
   */
  getYMD: function (SeparatorYMD = '-') {
    const date = new Date()
    const Year = date.getFullYear()
    const Month = format((date.getMonth() + 1).toString())
    const Day = format(date.getDate().toString())
    function format (str) {
      return str.length < 2 ? '0' + str : str
    }
    return Year + SeparatorYMD + Month + SeparatorYMD + Day
  },
  /**
   * 获取自定义分隔符的年月日时分秒
   * @param {年月日的分隔符} SeparatorYMD string
   * @param {日与时之间的分隔符} SeparatorDH string
   * @param {时分秒的分隔符} SeparatorHMS string
   * @returns string
   */
  getDate: function (
    SeparatorYMD = '-',
    SeparatorDH = ' ',
    SeparatorHMS = ':'
  ) {
    const date = new Date()
    const Year = date.getFullYear()
    const Month = format((date.getMonth() + 1).toString())
    const Day = format(date.getDate().toString())
    const Hours = format(date.getHours().toString())
    const Minutes = format(date.getMinutes().toString())
    const Seconds = format(date.getSeconds().toString())
    function format (str) {
      return str.length < 2 ? '0' + str : str
    }
    return (
      Year +
      SeparatorYMD +
      Month +
      SeparatorYMD +
      Day +
      SeparatorDH +
      Hours +
      SeparatorHMS +
      Minutes +
      SeparatorHMS +
      Seconds
    )
  },
  /**
   * 获取指定月份的总天数，默认本月
   * @param {月份} mouth Number
   * @param {年份_默认本年} year Number
   * @returns Number
   */
  getDaysPerMonth: function (mouth, year) {
    !mouth && (mouth = new Date().getMonth() + 1)
    !year && (year = new Date().getFullYear())
    // console.log(mouth)
    if (mouth === 1 || mouth === '01') return 31
    else if (mouth === 2 || mouth === '02') {
      if (this.isLeapYear(year)) return 29
      else return 28
    } else if (mouth === 3 || mouth === '03') return 31
    else if (mouth === 4 || mouth === '04') return 30
    else if (mouth === 5 || mouth === '05') return 31
    else if (mouth === 6 || mouth === '06') return 30
    else if (mouth === 7 || mouth === '07') return 31
    else if (mouth === 8 || mouth === '08') return 31
    else if (mouth === 9 || mouth === '09') return 30
    else if (mouth === 10 || mouth === '010') return 31
    else if (mouth === 11 || mouth === '011') return 30
    else if (mouth === 12 || mouth === '012') return 31
  },
  /**
   * 获取指定年份的总天数，默认本年
   * @param {年份} year Number
   * @returns Number
   */
  getDaysPerYear: function (year) {
    return this.isLeapYear(year) ? 365 : 366
  },
  /**
   * 获取当前的星期数
   * @param {需要显示什么类型_cn中文_en英文_默认数字} type String
   * @param {是否需要返回简写形式} Abbreviation Boolean
   * @returns String||Number
   */
  getWeek: function (type = 'number', Abbreviation = false) {
    type = type.toLowerCase()
    const week = new Date().getDay()
    if (/^zh|cn|zh-cn|chinese$/.test(type)) {
      switch (week) {
        case 1:
          return Abbreviation ? '周一' : '星期一'
        case 2:
          return Abbreviation ? '周二' : '星期二'
        case 3:
          return Abbreviation ? '周三' : '星期三'
        case 4:
          return Abbreviation ? '周四' : '星期四'
        case 5:
          return Abbreviation ? '周五' : '星期五'
        case 6:
          return Abbreviation ? '周六' : '星期六'
        case 0:
          return Abbreviation ? '周日' : '星期日'
      }
    } else if (/^en|english|en-us$/.test(type)) {
      switch (week) {
        case 1:
          return Abbreviation ? 'Mon' : 'Monday'
        case 2:
          return Abbreviation ? 'Tues' : 'Tuesday'
        case 3:
          return Abbreviation ? 'Wed' : 'Wednesday'
        case 4:
          return Abbreviation ? 'Thur' : 'Thursday'
        case 5:
          return Abbreviation ? 'Fir' : 'Friday'
        case 6:
          return Abbreviation ? 'Sat' : 'Saturday'
        case 0:
          return Abbreviation ? 'Sun' : 'Sunday'
      }
    } else if (/^number|num$/.test(type)) {
      return week
    }
  },
  /**
   * 获取今天为当月的第几天
   * @param {是否格式化_前面补零} format Boolean
   * @returns String||Number
   */
  getDay: function (format = false) {
    const day = new Date().getDate()
    return format ? Format(day) : day
    function Format (str) {
      return str.length < 2 ? '0' + str : str
    }
  },
  /**
   * 获取当前月份
   * @param {是否格式化_前面补零} format Boolean
   * @returns String||Number
   */
  getMonth: function (format = false) {
    const month = new Date().getMonth() + 1
    return format ? Format(month) : month
    function Format (str) {
      return str.length < 2 ? '0' + str : str
    }
  },
  /**
   * 获取当前年份
   * @returns Number
   */
  getYear: function () {
    return new Date().getFullYear()
  },
  /**
   * 获取当前小时数
   * @param {是否格式化_前面补零} format Boolean
   * @returns String||Number
   */
  getHours: function (format = false) {
    const Hours = new Date().getHours()
    return format ? Format(Hours) : Hours
    function Format (str) {
      return str.length < 2 ? '0' + str : str
    }
  },
  /**
   * 获取当前分钟数
   * @param {是否格式化_前面补零} format Boolean
   * @returns String||Number
   */
  getMinutes: function (format = false) {
    const Minutes = new Date().getMinutes()
    return format ? Format(Minutes) : Minutes
    function Format (str) {
      return str.length < 2 ? '0' + str : str
    }
  },
  /**
   * 获取当前秒数
   * @param {是否格式化_前面补零} format Boolean
   * @returns String||Number
   */
  getSeconds: function (format = false) {
    const Seconds = new Date().getSeconds()
    return format ? Format(Seconds) : Seconds
    function Format (str) {
      return str.length < 2 ? '0' + str : str
    }
  },
  /**
   * 获取指定时间戳，默认当前时间
   * @param {指定时间} time String
   * @returns Number
   */
  getStamp: function (time) {
    return time ? Date.parse(time) : Date.now()
  }
}

/**
 *  网络请求类
 *  需要时请使用new实例化
 */
class Net {
  constructor (initial = {}) {
    /**
     * 基地址
     */
    this.baseURL = ''
    /**
     * 第二层公共地址，接在基地址之后
     */
    this.secondURL = ''
    /**
     * 端口号
     */
    this.port = ''
    /**
     * 超时属性 毫秒
     */
    this.timeout = 0
    /**
     * 请求头
     * 写法：需要用-的符号，改用_
     * 首尾的_不会被转换
     * 确实需要下划线的，连写两个_，即__，用来标识，便会被转换成一个_
     */
    this.headers = {
      Accept: 'application/json, text/plain, */*',
      Content_Type: 'application/json'
    }
    /**
     * 授权头
     */
    this.Authorization = ''
    /**
     * 设置拦截器
     * 请求拦截器 Interceptor.request
     * 响应拦截器 Interceptor.response
     * 参数一致：
     *    参数一：成功||开始的回调
     *    参数二：失败的回调
     */
    this.Interceptor = {
      request: function (reqFn, errFn) {
        this.requestSuccess = reqFn
        this.requestError = errFn
        this.__rqi__ = true
      },
      response: function (resFn, errFn) {
        this.responseSuccess = resFn
        this.responseError = errFn
        this.__rsi__ = true
      },
      /**
       * 内部变量
       * 是否开启了响应拦截器
       */
      __rsi__: false,
      /**
       * 内部变量
       * 是否开启了请求拦截器
       */
      __rqi__: false,
      /**
       * 请求拦截器
       */
      requestSuccess: function () { },
      requestError: function () { },
      /**
       * 响应拦截器
       */
      responseSuccess: function () { },
      responseError: function () { }
    }

    /**
     * 根据传递参数，对构造函数进行初始化
     */
    if (!Is.EmptyObj(initial)) {
      if (Object.hasOwnProperty.call(initial, 'baseURL')) {
        this.baseURL = initial.baseURL
      }
      if (Object.hasOwnProperty.call(initial, 'secondURL')) {
        this.secondURL = initial.secondURL
      }
      if (Object.hasOwnProperty.call(initial, 'timeout')) {
        this.timeout = initial.timeout
      }
      if (Object.hasOwnProperty.call(initial, 'Authorization')) {
        this.Authorization = initial.Authorization
      }
    }
  }

  /**
   * POST请求，有请求参数，不带请求体
   * @param {参数传递} requestContent
   * @param {成功的回调} callbackResult
   * @param {失败的回调} callbackError
   * @returns Promise
   */
  postQuery (
    requestContent = {
      url: '',
      params: {},
      headers: {}
    },
    callbackResult,
    callbackError
  ) {
    requestContent.method = 'POST'
    return this.__YHBToolNetQuery(
      'Query',
      requestContent,
      callbackResult,
      callbackError
    )
  }

  /**
   * GET请求，有请求参数，不带请求体
   * @param {参数传递} requestContent
   * @param {成功的回调} callbackResult
   * @param {失败的回调} callbackError
   * @returns Promise
   */
  getQuery (
    requestContent = {
      url: '',
      params: {},
      headers: {}
    },
    callbackResult,
    callbackError
  ) {
    requestContent.method = 'GET'
    return this.__YHBToolNetQuery(
      'Query',
      requestContent,
      callbackResult,
      callbackError
    )
  }

  /**
   * PUT请求，有请求参数，不带请求体
   * @param {参数传递} requestContent
   * @param {成功的回调} callbackResult
   * @param {失败的回调} callbackError
   * @returns Promise
   */
  putQuery (
    requestContent = {
      url: '',
      params: {},
      headers: {}
    },
    callbackResult,
    callbackError
  ) {
    requestContent.method = 'PUT'
    return this.__YHBToolNetQuery(
      'Query',
      requestContent,
      callbackResult,
      callbackError
    )
  }

  /**
   * DELETE请求，有请求参数，不带请求体
   * @param {参数传递} requestContent
   * @param {成功的回调} callbackResult
   * @param {失败的回调} callbackError
   * @returns Promise
   */
  deleteQuery (
    requestContent = {
      url: '',
      params: {},
      headers: {}
    },
    callbackResult,
    callbackError
  ) {
    requestContent.method = 'DELETE'
    return this.__YHBToolNetQuery(
      'Query',
      requestContent,
      callbackResult,
      callbackError
    )
  }

  /**
   * PATCH请求，有请求参数，不带请求体
   * @param {参数传递} requestContent
   * @param {成功的回调} callbackResult
   * @param {失败的回调} callbackError
   * @returns Promise
   */
  patchQuery (
    requestContent = {
      url: '',
      params: {},
      headers: {}
    },
    callbackResult,
    callbackError
  ) {
    requestContent.method = 'PATCH'
    return this.__YHBToolNetQuery(
      'Query',
      requestContent,
      callbackResult,
      callbackError
    )
  }

  /**
   * POST请求，带请求体，没有请求参数
   * @param {参数传递} requestContent
   * @param {成功的回调} callbackResult
   * @param {失败的回调} callbackError
   * @returns Promise
   */
  postBody (
    requestContent = {
      url: '',
      data: {},
      headers: {}
    },
    callbackResult,
    callbackError
  ) {
    requestContent.method = 'POST'
    return this.__YHBToolNetQuery(
      'Body',
      requestContent,
      callbackResult,
      callbackError
    )
  }

  /**
   * GET请求，带请求体，没有请求参数
   * @param {参数传递} requestContent
   * @param {成功的回调} callbackResult
   * @param {失败的回调} callbackError
   * @returns Promise
   */
  getBody (
    requestContent = {
      url: '',
      data: {},
      headers: {}
    },
    callbackResult,
    callbackError
  ) {
    requestContent.method = 'GET'
    return this.__YHBToolNetQuery(
      'Body',
      requestContent,
      callbackResult,
      callbackError
    )
  }

  /**
   * PUT请求，带请求体，没有请求参数
   * @param {参数传递} requestContent
   * @param {成功的回调} callbackResult
   * @param {失败的回调} callbackError
   * @returns Promise
   */
  putBody (
    requestContent = {
      url: '',
      data: {},
      headers: {}
    },
    callbackResult,
    callbackError
  ) {
    requestContent.method = 'PUT'
    return this.__YHBToolNetQuery(
      'Body',
      requestContent,
      callbackResult,
      callbackError
    )
  }

  /**
   * DELETE请求，带请求体，没有请求参数
   * @param {参数传递} requestContent
   * @param {成功的回调} callbackResult
   * @param {失败的回调} callbackError
   * @returns Promise
   */
  deleteBody (
    requestContent = {
      url: '',
      data: {},
      headers: {}
    },
    callbackResult,
    callbackError
  ) {
    requestContent.method = 'DELETE'
    return this.__YHBToolNetQuery(
      'Body',
      requestContent,
      callbackResult,
      callbackError
    )
  }

  /**
   * PATCH请求，带请求体，没有请求参数
   * @param {参数传递} requestContent
   * @param {成功的回调} callbackResult
   * @param {失败的回调} callbackError
   * @returns Promise
   */
  patchBody (
    requestContent = {
      url: '',
      data: {},
      headers: {}
    },
    callbackResult,
    callbackError
  ) {
    requestContent.method = 'PATCH'
    return this.__YHBToolNetQuery(
      'Body',
      requestContent,
      callbackResult,
      callbackError
    )
  }

  /**
   * 上传文件，POST请求，带请求体，没有请求参数
   * 自动对文件进行FormData处理
   * 在第一个参数对象中，增加了file属性，属性值为数组，数组第一项为文件标识属性名
   * 数组第二项为文件数组
   * @param {参数传递} requestContent
   * @param {成功的回调} callbackResult
   * @param {失败的回调} callbackError
   * @returns Promise
   */
  uploadFile(requestContent = {
      url: '',
      data: {},
      file: ["",[]],
      headers: {}
    },
    callbackResult,
    callbackError) { 
      requestContent.method = 'POST'
      requestContent.headers.Content_Type = "multipart/form-data"
      let formData = new FormData()
      const fileName = requestContent.file[0]
      requestContent.file[1].forEach(item => { 
        formData.append(fileName,item)
      })
      requestContent.data[fileName] = formData
      delete requestContent.file
      return this.__YHBToolNetQuery(
        'Body',
        requestContent,
        callbackResult,
        callbackError
      )
  }

  /**
   * 自定义请求，可以指定请求方式，请求体与请求参数
   * @param {参数传递} requestContent
   * @param {成功的回调} callbackResult
   * @param {失败的回调} callbackError
   * @returns Promise
   */
  custom (
    requestContent = {
      url: '',
      params: {},
      data: {},
      method: '',
      headers: {}
    },
    callbackResult,
    callbackError
  ) {
    return this.__YHBToolNetQuery(
      'Double',
      requestContent,
      callbackResult,
      callbackError
    )
  }

  /**
   * 设置端口，跟在基地址与二层地址之后
   * @param {端口号} port Number||String
   */
  setPort (port) {
    let portStr = port + ''
    if (portStr.substring(0, 1) === ':') {
      portStr = portStr.substring(1, portStr.length)
    }
    if (Number(portStr)) {
      portStr = Number(portStr)
      if (portStr >= 0 && portStr <= 65535) {
        this.port = ':' + portStr
      }
    }
  }

  /**
   * 设置全局请求头
   * @param {请求头} headers Object
   */
  setHeaders (headers = {}) {
    for (const key in headers) {
      this.headers[key] = headers[key]
    }
  }

  /**
   * 关闭请求拦截器
   */
  closeRequestInterceptor () {
    this.Interceptor.__rqi__ = false
  }

  /**
   * 关闭响应拦截器
   */
  closeResponseInterceptor () {
    this.Interceptor.__rsi__ = false
  }

  /**
   *
   * 内部函数，请勿调用
   * 已有方法对其调用
   *
   */
  __YHBToolNetQuery (
    type = '',
    requestContent = {
      url: '',
      params: {},
      data: {},
      method: 'GET',
      headers: {}
    },
    callbackResult,
    callbackError = function () {}
  ) {
    // 解构
    const { url, params, data, method, headers } = requestContent
    // 实例化XMLHttpRequest
    const xhr = new XMLHttpRequest()
    if (this.Interceptor.__rqi__) {
      this.Interceptor.requestSuccess(xhr)
    }
    // 拼接url
    let URL = this.baseURL + this.secondURL + this.port + url
    if (type === 'Query' || type === 'Double') {
      // 处理查询参数
      let queryURL = '?'
      for (const key in params) {
        queryURL += key + '=' + params[key] + '&'
      }
      // 去掉最后的&字符
      queryURL = queryURL.substring(0, queryURL.length - 1)
      URL += queryURL
    }
    // 处理请求体
    const userData = JSON.stringify(data)
    // 储存全部请求头，先储存公共请求头，再添加局部请求头，以便本次请求局部覆盖公共
    const allHeaders = {}
    const baseHeaders = this.headers
    for (const key in baseHeaders) {
      allHeaders[key] = baseHeaders[key]
    }
    // 如果设置过Authorization，则为请求头添加Authorization校验
    if (this.Authorization) {
      allHeaders.Authorization = this.Authorization
    }
    for (const key in headers) {
      allHeaders[key] = headers[key]
    }

    // 创建Promise实例，开始请求
    const promise = new Promise((resolve, reject) => {
      
      xhr.open(method, URL)
      xhr.timeout = this.timeout
      // 准备请求头
      for (const key in allHeaders) {
        xhr.setRequestHeader(
          greatHumpToSeparator(key),
          allHeaders[key]
        )
      }
      /* 成功的请求 */
      xhr.addEventListener('loadend', () => {
        const resData = {}
        resData.data = {}
        resData.response = {}
        resData.request = {}

        resData.timeout = xhr.timeout
        resData.status = xhr.status
        resData.statusText = xhr.statusText
        resData.readyState = xhr.readyState

        let resHeaders = xhr.getAllResponseHeaders()
        const resHeadersObj = {}
        while (resHeaders.indexOf(':') !== -1) {
          const key = resHeaders.substring(0, resHeaders.indexOf(':'))
          resHeaders = Str.removeSpace(
            resHeaders.substring(
              resHeaders.indexOf(':') + 1,
              resHeaders.length
            )
          )
          const value = resHeaders.substring(
            0,
            resHeaders.indexOf('\r\n')
          )
          resHeaders = resHeaders.substring(
            resHeaders.indexOf('\r\n') + 2,
            resHeaders.length
          )
          resHeadersObj[key] = value
        }
        resData.response.headers = resHeadersObj
        resData.request.headers = allHeaders
        resData.request.method = method
        resData.request.url = URL
        resData.request.timeout = xhr.timeout
        if (type === 'Body' || type === 'Double') {
          resData.request.payload = data
        }
        if (xhr.response) {
          try {
            const temp = JSON.parse(xhr.response)
            resData.data = temp
          } catch (error) {
            resData.data = xhr.response
          }
          try {
            const temp = JSON.parse(xhr.responseText)
            resData.response.text = temp
          } catch (error) {
            resData.response.text = xhr.responseText
          }
          resData.response.url = xhr.responseURL
          resData.response.xml = xhr.responseXML
          resData.response.type = xhr.responseType
        }
        resData.xhr = xhr
        if (this.Interceptor.__rsi__) {
          if (xhr.status === 200) {
            resolve(this.Interceptor.responseSuccess(resData,xhr))
          } else {
            resolve(this.Interceptor.responseError(resData))
          }
        } else {
          resolve(resData)
        }
      })
      /* 失败的请求 */
      xhr.addEventListener('error', () => {
        const resData = {}
        resData.response = {}
        resData.request = {}

        resData.timeout = xhr.timeout
        resData.status = xhr.status
        resData.statusText = xhr.statusText
        resData.readyState = xhr.readyState

        let resHeaders = xhr.getAllResponseHeaders()
        const resHeadersObj = {}
        while (resHeaders.indexOf(':') !== -1) {
          const key = resHeaders.substring(0, resHeaders.indexOf(':'))
          resHeaders = Str.removeSpace(
            resHeaders.substring(
              resHeaders.indexOf(':') + 1,
              resHeaders.length
            )
          )
          const value = resHeaders.substring(
            0,
            resHeaders.indexOf('\r\n')
          )
          resHeaders = resHeaders.substring(
            resHeaders.indexOf('\r\n') + 2,
            resHeaders.length
          )
          resHeadersObj[key] = value
        }
        resData.response.headers = resHeadersObj
        resData.request.headers = allHeaders
        resData.request.method = method
        resData.request.url = URL
        resData.request.timeout = xhr.timeout
        if (type === 'Body' || type === 'Double') {
          resData.request.payload = data
        }
        if (xhr.response) {
          resData.response.text = JSON.parse(xhr.responseText)
          resData.response.url = xhr.responseURL
          resData.response.xml = xhr.responseXML
          resData.response.type = xhr.responseType
        }
        resData.name = 'netRequest 错误'
        resData.xhr = xhr
        console.error(resData)
        if (this.Interceptor.__rqi__) {
          reject(this.Interceptor.requestError(resData))
        } else {
          reject(resData)
        }
      })

      // 发送请求
      if (type === 'Body' || type === 'Double') xhr.send(userData)
      else xhr.send()
    })
    promise
      .then(res => {
        callbackResult(res)
      })
      .catch(err => {
        callbackError(err)
      })
    function greatHumpToSeparator (str = '') {
      const arr = Array.from(str)
      let is_ = false
      const temp = arr
        .map((item, index) => {
          if (
            index !== 0 &&
            index !== arr.length - 1 &&
            item === '_'
          ) {
            if (is_) {
              is_ = false
              return '_'
            } else {
              is_ = true
              return ''
            }
          } else {
            if (is_) {
              is_ = false
              return '-' + item
            } else {
              return item
            }
          }
        })
        .join('')
      return temp
    }
    return promise
  }
}

let __YHBToolModalToastBox = ''
let __YHBToolModalIsToast = false
/**
 * 浮窗类
 */
const Modal = {
  /**
   * 选择型浮窗，具有确定与取消按钮，出现时背景黑幕
   * @param {显示标题} title String
   * @param {显示内容} content String
   * @param {确认按钮执行函数} sureFunction Function
   */
  question: function (
    title = '',
    content = '',
    sureFunction = () => {}
  ) {
    if (document.querySelector('.__YHBToolQuestionModal')) {
      document.querySelector('.__YHBToolQuestionModal').remove()
    }
    const box = document.createElement('div')
    box.classList.add('__YHBToolQuestionModal')
    box.innerHTML = `
    <div id="__YHBToolQuestionModal_modalMask"></div>
    <div id="__YHBToolQuestionModal_content">
      <h4 id="__YHBToolQuestionModal_H">${title}</h4>
      <p id="__YHBToolQuestionModal_p">${content}</p>
      <div id="__YHBToolQuestionModal_Btn">
        <a id="__YHBToolQuestionModal_cancel" href="javascript:;">取消</a>
        <a id="__YHBToolQuestionModal_sure" href="javascript:;">确认</a>
      </div>
    </div>
    `
    document.body.append(box)
    boxStyle()
    setTimeout(() => {
      box.style.opacity = 1
    }, 50)
    // 确认按钮
    Listener('#__YHBToolQuestionModal_sure', 'click', () => {
      remove()
      sureFunction()
    })
    // 取消按钮
    Listener('#__YHBToolQuestionModal_cancel', 'click', () => {
      remove()
    })
    // 移除盒子
    function remove () {
      box.style.opacity = 0
      setTimeout(() => {
        box.remove()
      }, 300)
    }
    // style样式
    function boxStyle () {
      box.style.display = 'none'
      box.style.opacity = 0
      box.style.height = '100vh'
      box.style.width = '100vw'
      box.style.position = 'fixed'
      box.style.top = '0'
      box.style.left = '0'
      box.style.transition = 'all 0.2s'
      box.style.zIndex = '99999999999999999999999999999999999'
      const questionModalModalMask = dq(
        '#__YHBToolQuestionModal_modalMask'
      )
      const questionModalContent = dq(
        '#__YHBToolQuestionModal_content'
      )
      const questionModalH = dq('#__YHBToolQuestionModal_H')
      const questionModalP = dq('#__YHBToolQuestionModal_p')
      const questionModalSure = dq('#__YHBToolQuestionModal_sure')
      const questionModalBtn = dq('#__YHBToolQuestionModal_Btn')
      const questionModalCancel = dq('#__YHBToolQuestionModal_cancel')
      questionModalModalMask.style.height = '100%'
      questionModalModalMask.style.width = '100%'
      questionModalModalMask.style.backgroundColor =
        'rgba(0, 0, 0, 0.5)'
      questionModalModalMask.style.transition = 'all 0.3s'
      questionModalModalMask.style.zIndex =
        '99999999999999999999999999999999998'
      questionModalContent.style.width = '450px'
      questionModalContent.style.height = '200px'
      questionModalContent.style.position = 'absolute'
      questionModalContent.style.top = '20%'
      questionModalContent.style.left = '50%'
      questionModalContent.style.transform = 'translate(-50%, -50%)'
      questionModalContent.style.borderRadius = '15px'
      questionModalContent.style.transition = 'all 0.3s'
      questionModalContent.style.boxSizing = 'border-box'
      questionModalContent.style.backgroundColor = '#484848'
      questionModalContent.style.display = 'flex'
      questionModalContent.style.flexDirection = 'column'
      questionModalContent.style.justifyContent = 'space-between'
      questionModalContent.style.border = '1px solid #fff'
      questionModalH.style.padding = '10px'
      questionModalH.style.paddingBottom = '40px'
      questionModalH.style.height = '35px'
      questionModalH.style.lineHeight = '30px'
      questionModalH.style.fontSize = '20px'
      questionModalH.style.color = '#fff'
      questionModalH.style.fontWeight = 'normal'
      questionModalH.style.borderBottom = '1px solid'
      questionModalH.style.paddingLeft = '10px'
      questionModalP.style.flex = '1'
      questionModalP.style.color = '#fff'
      questionModalP.style.fontSize = '17px'
      questionModalP.style.paddingLeft = '10px'
      questionModalP.style.padding = '10px'
      questionModalBtn.style.display = 'flex'
      questionModalBtn.style.justifyContent = 'right'
      questionModalBtn.style.padding = '10px'
      questionModalSure.style.textAlign = 'center'
      questionModalSure.style.textDecoration = 'none'
      questionModalSure.style.color = '#fff'
      questionModalSure.style.display = 'block'
      questionModalSure.style.height = '32px'
      questionModalSure.style.lineHeight = '32px'
      questionModalSure.style.borderRadius = '8px'
      questionModalSure.style.marginRight = '10px'
      questionModalSure.style.width = '120px'
      questionModalSure.style.backgroundColor = 'rgb(39, 114, 255)'
      questionModalCancel.style.textAlign = 'center'
      questionModalCancel.style.textDecoration = 'none'
      questionModalCancel.style.color = '#fff'
      questionModalCancel.style.display = 'block'
      questionModalCancel.style.height = '32px'
      questionModalCancel.style.lineHeight = '32px'
      questionModalCancel.style.borderRadius = '8px'
      questionModalCancel.style.marginRight = '10px'
      questionModalCancel.style.width = '80px'
      questionModalCancel.style.backgroundColor = 'rgb(119, 119, 119)'
      box.style.display = 'block'
    }
    return box.outerHTML
  },

  /**
   * 提示型浮窗，具有确定按钮，出现时背景黑幕
   * @param {显示标题} title String
   * @param {显示内容} content String
   * @param {确认按钮执行函数} sureFunction Function
   */
  prompt: function (
    title = '',
    content = '',
    sureFunction = () => {}
  ) {
    if (document.querySelector('.__YHBToolPromptModal')) {
      document.querySelector('.__YHBToolPromptModal').remove()
    }
    const box = document.createElement('div')
    box.classList.add('__YHBToolPromptModal')
    box.innerHTML = `
    <div id="__YHBToolPromptModal_modalMask"></div>
    <div id="__YHBToolPromptModal_content">
      <h4 id="__YHBToolPromptModal_H">${title}</h4>
      <p id="__YHBToolPromptModal_p">${content}</p>
      <div id="__YHBToolPromptModal_Btn">
        <a id="__YHBToolPromptModal_sure" href="javascript:;">确认</a>
      </div>
    </div>
    `
    document.body.append(box)
    boxStyle()
    setTimeout(() => {
      box.style.opacity = 1
    }, 50)
    // 确认按钮
    Listener('#__YHBToolPromptModal_sure', 'click', () => {
      remove()
      sureFunction()
    })
    // 移除盒子
    function remove () {
      box.style.opacity = 0
      setTimeout(() => {
        box.remove()
      }, 300)
    }
    // style样式
    function boxStyle () {
      box.style.display = 'none'
      box.style.opacity = 0
      box.style.height = '100vh'
      box.style.width = '100vw'
      box.style.position = 'fixed'
      box.style.top = '0'
      box.style.left = '0'
      box.style.transition = 'all 0.2s'
      box.style.zIndex = '99999999999999999999999999999999999'
      const promptModalModalMask = dq(
        '#__YHBToolPromptModal_modalMask'
      )
      const promptModalContent = dq('#__YHBToolPromptModal_content')
      const promptModalH = dq('#__YHBToolPromptModal_H')
      const promptModalP = dq('#__YHBToolPromptModal_p')
      const promptModalSure = dq('#__YHBToolPromptModal_sure')
      const promptModalBtn = dq('#__YHBToolPromptModal_Btn')
      promptModalModalMask.style.height = '100%'
      promptModalModalMask.style.width = '100%'
      promptModalModalMask.style.backgroundColor =
        'rgba(0, 0, 0, 0.5)'
      promptModalModalMask.style.transition = 'all 0.3s'
      promptModalModalMask.style.zIndex =
        '99999999999999999999999999999999998'
      promptModalContent.style.width = '450px'
      promptModalContent.style.height = '200px'
      promptModalContent.style.position = 'absolute'
      promptModalContent.style.top = '20%'
      promptModalContent.style.left = '50%'
      promptModalContent.style.transform = 'translate(-50%, -50%)'
      promptModalContent.style.borderRadius = '15px'
      promptModalContent.style.transition = 'all 0.3s'
      promptModalContent.style.boxSizing = 'border-box'
      promptModalContent.style.backgroundColor = '#484848'
      promptModalContent.style.display = 'flex'
      promptModalContent.style.flexDirection = 'column'
      promptModalContent.style.justifyContent = 'space-between'
      promptModalContent.style.border = '1px solid #fff'
      promptModalH.style.padding = '10px'
      promptModalH.style.paddingBottom = '40px'
      promptModalH.style.height = '35px'
      promptModalH.style.lineHeight = '30px'
      promptModalH.style.fontSize = '20px'
      promptModalH.style.color = '#fff'
      promptModalH.style.fontWeight = 'normal'
      promptModalH.style.borderBottom = '1px solid'
      promptModalH.style.paddingLeft = '10px'
      promptModalP.style.flex = '1'
      promptModalP.style.color = '#fff'
      promptModalP.style.fontSize = '17px'
      promptModalP.style.paddingLeft = '10px'
      promptModalP.style.padding = '10px'
      promptModalBtn.style.display = 'flex'
      promptModalBtn.style.justifyContent = 'right'
      promptModalBtn.style.padding = '10px'
      promptModalSure.style.textAlign = 'center'
      promptModalSure.style.textDecoration = 'none'
      promptModalSure.style.color = '#fff'
      promptModalSure.style.display = 'block'
      promptModalSure.style.height = '32px'
      promptModalSure.style.lineHeight = '32px'
      promptModalSure.style.borderRadius = '8px'
      promptModalSure.style.marginRight = '10px'
      promptModalSure.style.width = '120px'
      promptModalSure.style.backgroundColor = 'rgb(39, 114, 255)'
      box.style.display = 'block'
    }
    return box.outerHTML
  },

  /**
   * 轻提示浮窗。
   * 可选位置：top、center、bottom
   * @param {显示内容} content String
   * @param {显示位置} position String
   * @param {背景颜色} backgroundColor String
   * @param {文字颜色} textColor String
   * @returns {返回模态框元素} element
   */
  toast: function (
    content = '',
    position = 'top',
    backgroundColor = 'rgba(0,0,0,0.7)',
    textColor = '#fff'
  ) {
    if (__YHBToolModalIsToast) {
      __YHBToolModalToastBox && __YHBToolModalToastBox.remove()
    }
    __YHBToolModalIsToast = true
    !position && (position = 'top')
    !backgroundColor && (backgroundColor = 'rgba(0,0,0,0.7)')
    !textColor && (textColor = '#fff')
    const box = document.createElement('div')
    box.classList.add('__YHBToolToastModal')
    box.style.backgroundColor = backgroundColor
    __YHBToolModalToastBox = box
    const p = document.createElement('p')
    p.classList.add('__YHBToolToastModalContent')
    p.style.color = textColor
    p.innerHTML = content
    box.appendChild(p)
    document.body.append(box)
    boxStyle()
    setTimeout(() => {
      box.style.opacity = 1
      remove()
    }, 50)
    // 移除盒子
    function remove () {
      setTimeout(() => {
        box.style.opacity = 0
        setTimeout(() => {
          box.remove()
          __YHBToolModalIsToast = false
        }, 400)
      }, 3000)
    }
    // style样式
    function boxStyle () {
      css.style('.__YHBToolToastModalContent', {
        fontSize: '13px',
        position: 'absolute',
        margin: 'auto',
        top: 0,
        right: 0,
        bottom: 0,
        left: 0,
        height: '100%',
        width: '100%',
        textAlign: 'center',
        lineHeight: '40px'
      })
      css.style('.__YHBToolToastModal', {
        display: 'none',
        opacity: 0,
        width: '280px',
        height: '40px',
        borderRadius: '5px',
        overflow: 'hidden',
        position: 'fixed',
        transform: 'translateX(-50%)',
        left: '50%',
        transition: 'all 0.5s',
        zIndex: '99999999999999999999999999999999999'
      })
      const divStyle = dq('.__YHBToolToastModal')
      if (position === 'top') {
        divStyle.style.top = '5%'
      } else if (position === 'center') {
        divStyle.style.top = '50%'
        divStyle.style.transform = 'translate(-50%,-50%)'
      } else if (position === 'bottom') {
        divStyle.style.bottom = '5%'
      } else {
        divStyle.style.top = '5%'
      }
      divStyle.style.display = 'flex'
    }
    return box.outerHTML
  },

  /**
   * 自定义浮窗，需要具有关闭元素，出现时背景黑幕
   * @param {需要显示的父元素} element
   * @param {点击让父元素关闭的元素或元素数组} moveElement string||array
   * @param {是否点击黑幕可以关闭元素} closeFromMask
   * @returns {返回对象中的close方法可以直接关闭模态框} Object
   */
  custom: function (element, moveElement, closeFromMask = true) {
    const ele = existElement(element, '未找到元素(Modal.custom)')
    let moveEle = [false, []]
    if (typeof moveElement === 'string') {
      moveEle = existElements(moveElement, '未找到元素(Modal.custom)')
    } else {
      moveElement.forEach(item => {
        const itemEle = existElement(item, '未找到元素(Modal.custom)')
        if (!itemEle[0]) return
        moveEle[0] = true
        moveEle[1].push(itemEle[1])
      })
    }

    if (ele[0] && moveEle[0]) {
      const Mask = document.createElement('div')
      Mask.id = '__YHBToolDivModalModalMask'
      document.body.prepend(Mask)
      Mask.style.opacity = 0
      Mask.style.position = 'fixed'
      Mask.style.top = '0'
      Mask.style.left = '0'
      Mask.style.height = '500%'
      Mask.style.width = '100%'
      Mask.style.backgroundColor = 'rgba(0, 0, 0, 0.7)'
      Mask.style.transition = 'all 0.3s'
      Mask.style.zIndex = '99999999999999999999999999999999999'
      ele[1].style.display = 'block'
      ele[1].style.opacity = 0
      ele[1].style.position = 'fixed'
      ele[1].style.top = '50%'
      ele[1].style.left = '50%'
      ele[1].style.transform = 'translate(-50%, -50%)'
      ele[1].style.transition = 'all 0.3s'
      ele[1].style.zIndex = '99999999999999999999999999999999999'
      moveEle[1].forEach(item => {
        item.style.cursor = 'pointer'
        item.addEventListener('click', function () {
          ele[1].style.opacity = 0
          Mask.style.opacity = 0
          setTimeout(() => {
            ele[1].style.display = 'none'
            Mask.style.display = 'none'
            Mask.remove()
          }, 350)
        })
      })
      setTimeout(() => {
        Mask.style.opacity = 1
        ele[1].style.opacity = 1
      }, 50)

      if (closeFromMask) {
        Mask.addEventListener('click', function () {
          ele[1].style.opacity = 0
          Mask.style.opacity = 0
          setTimeout(() => {
            ele[1].style.display = 'none'
            Mask.style.display = 'none'
            Mask.remove()
          }, 350)
        })
      }
      return {
        ele: ele[1],
        close: function () {
          const ele = this.ele
          ele.style.opacity = 0
          const mask = dqa('#__YHBToolDivModalModalMask')
          mask.forEach(item => {
            item.style.opacity = 0
            setTimeout(() => {
              ele.style.display = 'none'
              item.style.display = 'none'
              item.remove()
            }, 300)
          })
        }
      }
    }
  }
}

const __YHBToolFormStyleBorder = {}
const __YHBToolFormStyleBackground = {}
const __YHBToolFormStyleOutline = {}
let __YHBToolFormInputSelectNum = 0

/**
 * form表单类
 */
const form = {
  /**
   * 根据传入元素，整理表单全部value、值或选择情况，并执行回调函数。
   * 回调函数形参：value(表单全部值的对象)，item(表单父元素)
   * @param {表单区域父元素} element Element
   * @param {提交按钮执行函数} submitFunction Function
   * @param {执行函数形参表单全部值的对象} submitFunction_value Object
   * @param {执行函数形参表单父元素} submitFunction_item Element
   *
   */
  HTML: function (element, submitFunction = (value = {}) => {}) {
    const ele = existElement(element, '未找到元素(form.HTML):')
    if (ele[0]) {
      ele[1].addEventListener('submit', function (item) {
        item.preventDefault()
        const value = {}
        getTag("[type='text']", 'text')
        getTag("[type='password']", 'password')
        getTag('select', 'select')
        getTag('textarea', 'textarea')
        function getTag (tag, name) {
          if (!ele[1].querySelector(tag)) return
          ele[1].querySelectorAll(tag).forEach((item, index) => {
            !value[name] && (value[name] = {})
            value[name][
              item.name ? item.name : item.id ? item.id : name + index
            ] = item.value
          })
        }
        getCheck("[type='radio']")
        getCheck("[type='checkbox']")
        function getCheck (tag) {
          if (!ele[1].querySelector(tag)) return
          const nameList = []
          let num = 0
          ele[1].querySelectorAll(tag).forEach(item => {
            !nameList.length && nameList.push(item.name)
            nameList[num] !== item.name &&
              ++num &&
              nameList.push(item.name)
          })
          nameList.forEach(item => {
            ele[1]
              .querySelectorAll(tag + `[name=${item}]`)
              .forEach(item => {
                if (item.type === 'checkbox') {
                  !value.checkbox && (value.checkbox = {})
                  !value.checkbox[item.name] &&
                    (value.checkbox[item.name] = {
                      status: [],
                      checkedValue: []
                    })
                  value.checkbox[item.name].status.push(item.checked)
                  item.checked &&
                    value.checkbox[item.name].checkedValue.push(
                      item.value
                    )
                }
                if (item.type === 'radio') {
                  !value.radio && (value.radio = {})
                  !value.radio[item.name] &&
                    (value.radio[item.name] = {
                      status: [],
                      checkedValue: ''
                    })
                  value.radio[item.name].status.push(item.checked)
                  item.checked &&
                    (value.radio[item.name].checkedValue = item.value)
                }
              })
          })
        }
        getFile("[type='file']", 'file')
        function getFile (tag, name) {
          if (!ele[1].querySelector(tag)) return
          ele[1].querySelectorAll(tag).forEach((item, index) => {
            !value[name] && (value[name] = {})
            const key = item.name
              ? item.name
              : item.id
                ? item.id
                : name + index
            value[name][key] = []
            const files = item.files
            for (let i = 0; i < files.length; i++) {
              value[name][key][i] = files[i]
            }
          })
        }
        submitFunction(value, item)
      })
    }
  },
  /**
   * 根据传入元素，整理表单全部value、值或选择情况，并返回表单数据
   * @param {表单区域父元素} element Element
   * @returns data
   */
  getValue: function (element) {
    const ele = existElement(element, '未找到元素(form.getValue):')
    if (ele[0]) {
      const value = {}
      getTag("[type='text']", 'text')
      getTag("[type='password']", 'password')
      getTag('select', 'select')
      getTag('textarea', 'textarea')
      function getTag (tag, name) {
        if (!element.querySelector(tag)) return
        element.querySelectorAll(tag).forEach((item, index) => {
          !value[name] && (value[name] = {})
          value[name][
            item.name ? item.name : item.id ? item.id : name + index
          ] = item.value
        })
      }
      getCheck("[type='radio']")
      getCheck("[type='checkbox']")
      function getCheck (tag) {
        if (!ele[1].querySelector(tag)) return
        const nameList = []
        let num = 0
        ele[1].querySelectorAll(tag).forEach(item => {
          !nameList.length && nameList.push(item.name)
          nameList[num] !== item.name &&
            ++num &&
            nameList.push(item.name)
        })
        nameList.forEach(item => {
          ele[1]
            .querySelectorAll(tag + `[name=${item}]`)
            .forEach(item => {
              if (item.type === 'checkbox') {
                !value.checkbox && (value.checkbox = {})
                !value.checkbox[item.name] &&
                  (value.checkbox[item.name] = {
                    status: [],
                    checkedValue: []
                  })
                value.checkbox[item.name].status.push(item.checked)
                item.checked &&
                  value.checkbox[item.name].checkedValue.push(
                    item.value
                  )
              }
              if (item.type === 'radio') {
                !value.radio && (value.radio = {})
                !value.radio[item.name] &&
                  (value.radio[item.name] = {
                    status: [],
                    checkedValue: ''
                  })
                value.radio[item.name].status.push(item.checked)
                item.checked &&
                  (value.radio[item.name].checkedValue = item.value)
              }
            })
        })
      }
      getFile("[type='file']", 'file')
      function getFile (tag, name) {
        if (!ele[1].querySelector(tag)) return
        ele[1].querySelectorAll(tag).forEach((item, index) => {
          !value[name] && (value[name] = {})
          const key = item.name
            ? item.name
            : item.id
              ? item.id
              : name + index
          value[name][key] = []
          const files = item.files
          for (let i = 0; i < files.length; i++) {
            value[name][key][i] = files[i]
          }
        })
      }
      return value
    }
  },
  /**
   * 根据传入元素，整理表单全部value、值或选择情况，会对空内容进行标红处理，并执行回调函数。
   * 回调函数形参：value(表单全部值的对象)，isEmpty(是否有空内容元素)，isDetail(是否含有自定义错误)，item(表单父元素)
   * @param {表单区域父元素} element Element
   * @param {是否开启空内容检测} admitEmpty Boolean
   * @param {表单元素错误详情控制} detail
   * @param {提交按钮执行函数} submitFunction Function
   * @param {执行函数形参表单全部值的对象} submitFunction_value Object
   * @param {执行函数形参是否有空内容元素} submitFunction_isEmpty Boolean
   * @param {执行函数形参是否含有自定义错误} submitFunction_isDetail Boolean
   * @param {执行函数形参表单父元素} submitFunction_item Element
   */
  /* detail格式：
  [
    {
      //class，name，id 三选一进行定位
      //仅仅只匹配第一个符合的元素
      class:"类名",
      name:"",
      id:"",

      //为空判断
      empty:true,
      //空值执行函数
      toEmpty:function (){},

      //长度限定
      length:[6,30],
      //长度不符执行函数
      toLength:function (){},

      //正则限定
      reg:"",
      //正则不符执行函数
      toReg:function (){},

      //以上判断有任意一个不成功的执行函数
      to:function (){}
    }
  ]
  */
  require: function (
    element,
    admitEmpty = true,
    detail = [],
    submitFunction = (value = {}, isEmpty, item) => {}
  ) {
    const ele = existElement(element, '未找到元素(form.require):')
    if (ele[0]) {
      const __YHBToolFormStyleBorder = {}
      const __YHBToolFormStyleBackground = {}
      const __YHBToolFormStyleOutline = {}
      let arrNum = 0
      ele[1].addEventListener('submit', function (item) {
        let isEmpty = false
        item.preventDefault()
        if (admitEmpty) {
          styleRe(__YHBToolFormStyleBorder, 'border')
          styleRe(__YHBToolFormStyleBackground, 'backgroundColor')
          styleRe(__YHBToolFormStyleOutline, 'outline')
        }
        function styleRe (obj, styleKey) {
          if (!Is.EmptyObj(obj)) {
            for (const key in obj) {
              obj[key].style[styleKey] = key.substring(
                0,
                key.indexOf('**')
              )
            }
          }
        }
        const value = {}
        getTag("[type='text']", 'text')
        getTag("[type='password']", 'password')
        getTag('select', 'select')
        getTag('textarea', 'textarea')
        function styleAdd (item) {
          __YHBToolFormStyleBorder[
            item.style.border + '**' + arrNum++
          ] = item
          __YHBToolFormStyleBackground[
            item.style.backgroundColor + '**' + arrNum++
          ] = item
          item.style.border = '2px solid rgb(255, 105, 105)'
          item.style.backgroundColor = 'rgb(255, 228, 228)'
        }
        function getTag (tag, name) {
          if (!ele[1].querySelector(tag)) return
          ele[1].querySelectorAll(tag).forEach((item, index) => {
            !value[name] && (value[name] = {})
            if (admitEmpty) {
              if (
                (name === 'text' ||
                  name === 'textarea' ||
                  name === 'password') &&
                item.value === ''
              ) {
                isEmpty = true
                styleAdd(item)
              }
              if (
                name === 'select' &&
                item.value === item.children[0].value
              ) {
                isEmpty = true
                styleAdd(item)
              }
            }
            value[name][
              item.name ? item.name : item.id ? item.id : name + index
            ] = item.value
          })
        }
        getCheck("[type='radio']")
        getCheck("[type='checkbox']")
        function getCheck (tag) {
          if (!ele[1].querySelector(tag)) return
          const nameList = []
          let num = 0
          ele[1].querySelectorAll(tag).forEach(item => {
            !nameList.length && nameList.push(item.name)
            nameList[num] !== item.name &&
              ++num &&
              nameList.push(item.name)
          })
          nameList.forEach(item => {
            ele[1]
              .querySelectorAll(tag + `[name=${item}]`)
              .forEach(item => {
                if (item.type === 'checkbox') {
                  !value.checkbox && (value.checkbox = {})
                  !value.checkbox[item.name] &&
                    (value.checkbox[item.name] = {
                      status: [],
                      checkedValue: []
                    })
                  value.checkbox[item.name].status.push(item.checked)
                  item.checked &&
                    value.checkbox[item.name].checkedValue.push(
                      item.value
                    )
                }
                if (item.type === 'radio') {
                  !value.radio && (value.radio = {})
                  !value.radio[item.name] &&
                    (value.radio[item.name] = {
                      status: [],
                      checkedValue: ''
                    })
                  value.radio[item.name].status.push(item.checked)
                  item.checked &&
                    (value.radio[item.name].checkedValue = item.value)
                }
              })
          })
        }
        if (admitEmpty) {
          styleAdd2('checkbox')
          styleAdd2('radio')
        }
        function styleAdd2 (tagName) {
          if (value[tagName]) {
            for (const key in value[tagName]) {
              if (
                !value[tagName][key].status.some(
                  item => item === true
                )
              ) {
                isEmpty = true
                document
                  .querySelectorAll(
                    `[type='${tagName}'][name='${key}']`
                  )
                  .forEach(item => {
                    __YHBToolFormStyleOutline[
                      item.style.outline + '**' + arrNum++
                    ] = item
                    item.style.outline =
                      '2px solid rgb(255, 105, 105)'
                  })
              }
            }
          }
        }
        getFile("[type='file']", 'file')
        function getFile (tag, name) {
          if (!ele[1].querySelector(tag)) return
          ele[1].querySelectorAll(tag).forEach((item, index) => {
            !value[name] && (value[name] = {})
            const key = item.name
              ? item.name
              : item.id
                ? item.id
                : name + index
            value[name][key] = []
            const files = item.files
            for (let i = 0; i < files.length; i++) {
              value[name][key][i] = files[i]
            }
          })
        }
        if (admitEmpty && value.file) {
          for (const key in value.file) {
            if (!value.file[key].length) {
              isEmpty = true
              document
                .querySelectorAll(`[type='file'][name='${key}']`)
                .forEach(item => {
                  styleAdd(item)
                })
            }
          }
        }
        let isDetail = false
        detail.forEach(item => {
          if (item.class || item.id || item.name) {
            let eleName = ''
            if (item.class) eleName = `.${item.class}`
            if (item.id) eleName = `#${item.id}`
            if (item.name) eleName = `[name=${item.name}]`
            const ele = document.querySelector(eleName)
            const value = ele.value
            if (
              item.empty &&
              (value === '' || value === null || value === undefined)
            ) {
              isDetail = true
              item.toEmpty && item.toEmpty()
              item.to && item.to()
              return
            }
            if (
              item.length &&
              !(
                value.length >= item.length[0] &&
                value.length <= item.length[1]
              )
            ) {
              isDetail = true
              item.toLength && item.toLength()
              item.to && item.to()
              return
            }
            if (item.reg) {
              let regStr = String(item.reg)
              if (regStr.substring(0, 1) === '/') {
                regStr = regStr.substring(1, regStr.length - 1)
              }
              if (!new RegExp(regStr).test(value)) {
                isDetail = true
                item.toReg && item.toReg()
                item.to && item.to()
                return
              }
            }
            isDetail = false
          }
        })
        submitFunction(value, isEmpty, isDetail, item)
      })
    }
  },
  /**
   * 根据传入元素，整理表单全部value、值或选择情况，会对空内容进行标红处理，并返回表单数据
   * @param {表单区域父元素} element Element
   * @param {是否开启空内容检测} admitEmpty Boolean
   * @param {表单元素错误详情控制} detail
   * @returns 数据与判断结果 {data,isEmpty,isDetail}
   */
  getValueRequire: function (
    element,
    admitEmpty = true,
    detail = []
  ) {
    const ele = existElement(
      element,
      '未找到元素(form.getValueRequire):'
    )
    if (ele[0]) {
      let isEmpty = false
      let arrNum = 0
      if (admitEmpty) {
        styleRe(__YHBToolFormStyleBorder, 'border')
        styleRe(__YHBToolFormStyleBackground, 'backgroundColor')
        styleRe(__YHBToolFormStyleOutline, 'outline')
      }
      function styleRe (obj, styleKey) {
        if (!Is.EmptyObj(obj)) {
          for (const key in obj) {
            obj[key].style[styleKey] = key.substring(
              0,
              key.indexOf('**')
            )
          }
        }
      }
      const value = {}
      getTag("[type='text']", 'text')
      getTag("[type='password']", 'password')
      getTag('select', 'select')
      getTag('textarea', 'textarea')
      function styleAdd (item) {
        __YHBToolFormStyleBorder[
          item.style.border + '**' + arrNum++
        ] = item
        __YHBToolFormStyleBackground[
          item.style.backgroundColor + '**' + arrNum++
        ] = item
        item.style.border = '2px solid rgb(255, 105, 105)'
        item.style.backgroundColor = 'rgb(255, 228, 228)'
      }
      function getTag (tag, name) {
        if (!ele[1].querySelector(tag)) return
        ele[1].querySelectorAll(tag).forEach((item, index) => {
          !value[name] && (value[name] = {})
          if (admitEmpty) {
            if (
              (name === 'text' ||
                name === 'textarea' ||
                name === 'password') &&
              item.value === ''
            ) {
              isEmpty = true
              styleAdd(item)
            }
            if (
              name === 'select' &&
              item.value === item.children[0].value
            ) {
              isEmpty = true
              styleAdd(item)
            }
          }
          value[name][
            item.name ? item.name : item.id ? item.id : name + index
          ] = item.value
        })
      }
      getCheck("[type='radio']")
      getCheck("[type='checkbox']")
      function getCheck (tag) {
        if (!ele[1].querySelector(tag)) return
        const nameList = []
        let num = 0
        ele[1].querySelectorAll(tag).forEach(item => {
          !nameList.length && nameList.push(item.name)
          nameList[num] !== item.name &&
            ++num &&
            nameList.push(item.name)
        })
        nameList.forEach(item => {
          ele[1]
            .querySelectorAll(tag + `[name=${item}]`)
            .forEach(item => {
              if (item.type === 'checkbox') {
                !value.checkbox && (value.checkbox = {})
                !value.checkbox[item.name] &&
                  (value.checkbox[item.name] = {
                    status: [],
                    checkedValue: []
                  })
                value.checkbox[item.name].status.push(item.checked)
                item.checked &&
                  value.checkbox[item.name].checkedValue.push(
                    item.value
                  )
              }
              if (item.type === 'radio') {
                !value.radio && (value.radio = {})
                !value.radio[item.name] &&
                  (value.radio[item.name] = {
                    status: [],
                    checkedValue: ''
                  })
                value.radio[item.name].status.push(item.checked)
                item.checked &&
                  (value.radio[item.name].checkedValue = item.value)
              }
            })
        })
      }
      if (admitEmpty) {
        styleAdd2('checkbox')
        styleAdd2('radio')
      }
      function styleAdd2 (tagName) {
        if (value[tagName]) {
          for (const key in value[tagName]) {
            if (
              !value[tagName][key].status.some(item => item === true)
            ) {
              isEmpty = true
              document
                .querySelectorAll(
                  `[type='${tagName}'][name='${key}']`
                )
                .forEach(item => {
                  __YHBToolFormStyleOutline[
                    item.style.outline + '**' + arrNum++
                  ] = item
                  item.style.outline = '2px solid rgb(255, 105, 105)'
                })
            }
          }
        }
      }
      getFile("[type='file']", 'file')
      function getFile (tag, name) {
        if (!ele[1].querySelector(tag)) return
        ele[1].querySelectorAll(tag).forEach((item, index) => {
          !value[name] && (value[name] = {})
          const key = item.name
            ? item.name
            : item.id
              ? item.id
              : name + index
          value[name][key] = []
          const files = item.files
          for (let i = 0; i < files.length; i++) {
            value[name][key][i] = files[i]
          }
        })
      }
      if (admitEmpty && value.file) {
        for (const key in value.file) {
          if (!value.file[key].length) {
            isEmpty = true
            document
              .querySelectorAll(`[type='file'][name='${key}']`)
              .forEach(item => {
                styleAdd(item)
              })
          }
        }
      }
      let isDetail = false
      detail.forEach(item => {
        if (item.class || item.id || item.name) {
          let eleName = ''
          if (item.class) eleName = `.${item.class}`
          if (item.id) eleName = `#${item.id}`
          if (item.name) eleName = `[name=${item.name}]`
          const ele = document.querySelector(eleName)
          const value = ele.value
          if (
            item.empty &&
            (value === '' || value === null || value === undefined)
          ) {
            isDetail = true
            item.toEmpty && item.toEmpty()
            item.to && item.to()
            return
          }
          if (
            item.length &&
            !(
              value.length >= item.length[0] &&
              value.length <= item.length[1]
            )
          ) {
            isDetail = true
            item.toLength && item.toLength()
            item.to && item.to()
            return
          }
          if (item.reg) {
            let regStr = String(item.reg)
            if (regStr.substring(0, 1) === '/') {
              regStr = regStr.substring(1, regStr.length - 1)
            }
            if (!new RegExp(regStr).test(value)) {
              isDetail = true
              item.toReg && item.toReg()
              item.to && item.to()
              return
            }
          }
          isDetail = false
        }
      })
      return { value, isEmpty, isDetail }
    }
  },

  /**
   * 睁眼SVG图像
   * 用于密码框显示
   * 已有方法对其进行调用
   */
  openEyeSVG:
    '<svg t="1695451059690" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1723" width="200" height="200"><path d="M512 832c-156.448 0-296.021333-98.730667-418.410667-291.605333a52.938667 52.938667 0 0 1 0-56.789334C215.978667 290.730667 355.552 192 512 192c156.448 0 296.021333 98.730667 418.410667 291.605333a52.938667 52.938667 0 0 1 0 56.789334C808.021333 733.269333 668.448 832 512 832z m0-576c-129.514667 0-249.461333 83.850667-360.117333 256C262.538667 684.149333 382.485333 768 512 768c129.514667 0 249.461333-83.850667 360.117333-256C761.461333 339.850667 641.514667 256 512 256z m0 405.333333c-83.210667 0-150.666667-66.858667-150.666667-149.333333S428.789333 362.666667 512 362.666667s150.666667 66.858667 150.666667 149.333333S595.210667 661.333333 512 661.333333z m0-64c47.552 0 86.101333-38.208 86.101333-85.333333S559.552 426.666667 512 426.666667c-47.552 0-86.101333 38.208-86.101333 85.333333s38.549333 85.333333 86.101333 85.333333z" fill="#000000" p-id="1724"></path></svg>',
  /**
   * 闭眼SVG图像
   * 用于密码框显示
   * 已有方法对其进行调用
   */
  closeEyeSVG:
    '<svg t="1695451008027" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1585" width="200" height="200"><path d="M930.024 339.358c8.607-12.84 5.644-29.914-5.644-39.933-12.84-10.018-29.915-7.196-39.933 5.644-1.411 1.411-159.731 188.235-347.965 188.235-182.59 0-347.966-188.235-349.377-189.646-10.018-11.43-28.503-12.84-39.932-2.822-11.43 10.019-12.84 28.503-2.822 39.933 2.822 4.233 37.11 42.755 91.295 85.51l-72.81 75.632c-11.43 11.43-10.02 29.914 1.41 39.933 2.822 5.644 10.019 8.607 17.074 8.607 7.196 0 14.252-2.822 20.037-8.607l78.454-81.277c37.111 25.681 81.277 49.951 129.817 67.025l-29.914 101.314c-4.233 15.662 4.233 31.325 20.037 35.7h8.607c12.84 0 24.27-8.608 27.092-21.449l29.915-101.313c22.859 4.233 47.129 7.196 71.258 7.196 24.27 0 48.54-2.822 71.258-7.196l29.914 99.902c2.822 12.84 15.663 21.448 27.092 21.448 2.823 0 5.645 0 7.197-1.41 15.662-4.234 24.27-20.038 20.037-35.7l-30.338-99.903c48.54-17.074 92.706-41.344 129.817-67.025l77.043 79.866c5.644 5.644 12.84 8.607 20.037 8.607s14.252-2.822 20.037-8.607c11.43-11.43 11.43-28.504 1.411-39.933l-72.669-75.632c58.276-42.755 92.565-84.1 92.565-84.1z m0 0" p-id="1586"></path></svg>',

  /**
   * 为密码框架加上眼睛效果，并控制密码框类型变换。
   * 具有默认图标效果。
   * 也可以通过传参(iconFontClose、iconFontOpen)来自定义调整图案。
   * 如果自定义调整，需要将两个形参都传递
   * @param {密码框元素} element Element
   * @param {闭眼字体图标_可选} iconFontClose String
   * @param {睁眼字体图标_可选} iconFontOpen String
   * @returns span Element
   */
  eye: function (
    element = '',
    iconFontClose = '',
    iconFontOpen = ''
  ) {
    const ele = existElement(element, '未找到元素(form.eye):')
    if (ele[0]) {
      if (ele[1].type !== 'password') {
        return console.error('非密码框(form.eye)：' + ele[1])
      }
      const span = document.createElement('span')
      if (iconFontClose && iconFontOpen) {
        span.classList.add(`${iconFontClose}`)
      } else {
        span.innerHTML = this.closeEyeSVG
      }

      span.style.position = 'absolute'
      span.style.display = 'flex'
      span.style.justifyContent = 'center'
      span.style.alignItems = 'center'
      span.style.cursor = 'pointer'
      span.style.overflow = 'hidden'
      let spanHeight = 21
      let spanWidth = 21
      style()
      ele[1].after(span)
      if (__YHBToolIsMobile) {
        let isClick = false
        span.addEventListener('click', () => {
          if (!isClick) {
            if (iconFontClose && iconFontOpen) {
              span.classList.remove(`${iconFontClose}`)
              span.classList.add(`${iconFontOpen}`)
            } else {
              span.innerHTML = this.openEyeSVG
            }
            ele[1].type = 'text'
          } else {
            if (iconFontClose && iconFontOpen) {
              span.classList.remove(`${iconFontOpen}`)
              span.classList.add(`${iconFontClose}`)
            } else {
              span.innerHTML = this.closeEyeSVG
            }
            ele[1].type = 'password'
          }
          isClick = !isClick
        })
      } else {
        span.addEventListener('mousedown', () => {
          if (iconFontClose && iconFontOpen) {
            span.classList.remove(`${iconFontClose}`)
            span.classList.add(`${iconFontOpen}`)
          } else {
            span.innerHTML = this.openEyeSVG
          }
          ele[1].type = 'text'
        })
        span.addEventListener('mouseup', () => {
          if (iconFontClose && iconFontOpen) {
            span.classList.remove(`${iconFontOpen}`)
            span.classList.add(`${iconFontClose}`)
          } else {
            span.innerHTML = this.closeEyeSVG
          }
          ele[1].type = 'password'
        })
        span.addEventListener('mouseout', () => {
          if (iconFontClose && iconFontOpen) {
            span.classList.remove(`${iconFontOpen}`)
            span.classList.add(`${iconFontClose}`)
          } else {
            span.innerHTML = this.closeEyeSVG
          }
          ele[1].type = 'password'
        })
      }
      window.onresize = style()
      function style () {
        spanHeight = ele[1].offsetHeight
        spanWidth = ele[1].offsetHeight
        span.style.height = spanHeight + 'px'
        span.style.width = spanWidth + 'px'
        span.style.top =
          ele[1].offsetTop +
          (ele[1].offsetHeight - spanHeight) / 2 +
          'px'
        span.style.left =
          ele[1].offsetLeft + ele[1].offsetWidth - spanWidth + 'px'
      }
      return span
    }
  },
  /**
   * 为多行文本加上字数显示与限制字数
   * @param {多行文本元素} element Element
   * @param {限定字数} length Number
   * @returns span Element
   */
  textareaLength: function (element = '', length = 20) {
    const ele = existElement(
      element,
      '未找到元素(form.textareaLength):'
    )
    if (ele[0]) {
      if (ele[1].tagName !== 'TEXTAREA') {
        return console.error(
          '非多行文本输入框(form.textareaLength)：' + ele[1]
        )
      }
      const span = document.createElement('span')
      span.innerText = `0/${length}`
      span.style.display = 'block'
      span.style.position = 'absolute'
      span.style.color = 'rgb(166, 166, 166)'
      span.style.opacity = 0
      span.style.transition = 'all 0.2s'
      style()
      ele[1].after(span)
      window.onresize = style()
      window.addEventListener('resize', () => style())
      ele[1].addEventListener('mousemove', () => style())
      ele[1].addEventListener('focus', () => (span.style.opacity = 1))
      ele[1].addEventListener('blur', () => (span.style.opacity = 0))
      let isComposition = false
      ele[1].addEventListener(
        'compositionstart',
        () => (isComposition = true)
      )
      ele[1].addEventListener('compositionend', () => {
        isComposition = false
        to()
      })
      ele[1].addEventListener('input', () => {
        if (!isComposition) to()
      })
      function to () {
        if (ele[1].value.length >= length) {
          ele[1].value = ele[1].value.substring(0, length)
          span.style.color = 'rgb(2, 159, 2)'
        } else {
          span.style.color = 'rgb(166, 166, 166)'
        }
        span.innerText = `${ele[1].value.length}/${length}`
      }
      function style () {
        span.style.transition = 'none'
        span.style.fontSize = ele[1].style.fontSize + 'px'
        span.style.top = ele[1].offsetTop + ele[1].offsetHeight + 'px'
        span.style.left =
          ele[1].offsetLeft + ele[1].offsetWidth + 'px'
        span.style.transform = 'translate(-130%,-130%)'
        span.style.transition = 'all 0.2s'
      }
      return span
    }
  },
  /**
   * 为input输入框加上字数显示与限制字数
   * @param {input输入框元素} element Element
   * @param {限定字数} length Number
   * @returns span Element
   */
  inputLength: function (element = '', length = 20) {
    const ele = existElement(element, '未找到元素(form.inputLength):')
    if (ele[0]) {
      if (ele[1].tagName !== 'INPUT') {
        return console.error('非输入框(form.inputLength)：' + ele[1])
      }
      const span = document.createElement('span')
      span.innerText = `0/${length}`
      span.style.display = 'block'
      span.style.position = 'absolute'
      span.style.color = 'rgb(166, 166, 166)'
      span.style.opacity = 0
      span.style.transition = 'all 0.2s'
      style()
      ele[1].after(span)
      window.onresize = style()
      window.addEventListener('resize', () => style())
      ele[1].addEventListener('mousemove', () => style())
      ele[1].addEventListener('focus', () => (span.style.opacity = 1))
      ele[1].addEventListener('blur', () => (span.style.opacity = 0))
      let isComposition = false
      ele[1].addEventListener(
        'compositionstart',
        () => (isComposition = true)
      )
      ele[1].addEventListener('compositionend', () => {
        isComposition = false
        to()
      })
      ele[1].addEventListener('input', () => {
        if (!isComposition) to()
      })
      function to () {
        if (ele[1].value.length >= length) {
          ele[1].value = ele[1].value.substring(0, length)
          span.style.color = 'rgb(2, 159, 2)'
        } else {
          span.style.color = 'rgb(166, 166, 166)'
        }
        span.innerText = `${ele[1].value.length}/${length}`
      }
      function style () {
        span.style.transition = 'none'
        span.style.fontSize = ele[1].style.fontSize + 'px'
        span.style.top = ele[1].offsetTop + ele[1].offsetHeight + 'px'
        span.style.left =
          ele[1].offsetLeft + ele[1].offsetWidth + 'px'
        span.style.transform = 'translate(-130%,-100%)'
        span.style.transition = 'all 0.2s'
      }
      return span
    }
  },
  /**
   * 方向箭头SVG图像
   * 默认向下
   * 用于input框显示
   * 已有方法对其进行调用
   */
  directionArrowSVG:
    '<svg t="1696490095207" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1447" width="200" height="200"><path d="M512 688.64c-6.656 0-13.312-2.56-17.92-7.68l-302.08-302.08c-10.24-10.24-10.24-26.112 0-36.352s26.112-10.24 36.352 0l284.16 284.16L796.16 343.04c10.24-10.24 26.112-10.24 36.352 0s10.24 26.112 0 36.352l-302.08 302.08c-5.12 4.608-11.776 7.168-18.432 7.168z" fill="#8a8a8a" p-id="1448"></path></svg>',

  /**
   * 为input输入框加上下拉选项
   * @param {input输入框元素} element Element
   * @param {选项数组} data Array||Object
   * @param {输入值没有模糊匹配到data数组里的数据时显示的文字} notFound String
   * @param {是否限制输入框必须匹配数据_不匹配则清空输入框} limitation Boolean
   * @param {回调函数_获取点击之后的值} callback Function
   * @param {回调函数形参_返回数组索引或对象的key} callback_value String||Number
   * @returns {下拉三角形元素} span Element
   */
  inputSelect: function (
    element = '',
    data = [],
    notFound = '暂无数据',
    limitation = false,
    callback = function (value) {}
  ) {
    const ele = existElement(element, '未找到元素(form.inputSelect):')
    if (ele[0]) {
      if (ele[1].tagName !== 'INPUT') {
        return console.error('非输入框(form.inputSelect)：' + ele[1])
      }
      for (let i = 0; i <= __YHBToolFormInputSelectNum; i++) {
        ele[1].classList.forEach(item => {
          if (item === `form-input-select-elementClassName${i}`) {
            dq(`.form-input-select-div-ele${i}`).remove()
            dq(`.form-input-select-span-ele${i}`).remove()
            ele[1].classList.remove(
              `form-input-select-elementClassName${i}`
            )
          }
        })
      }
      ++__YHBToolFormInputSelectNum
      const eleClassName = `form-input-select-elementClassName${__YHBToolFormInputSelectNum}`
      const divClassName = `form-input-select-div-ele${__YHBToolFormInputSelectNum}`
      const spanClassName = `form-input-select-span-ele${__YHBToolFormInputSelectNum}`
      ele[1].classList.add(eleClassName)
      const div = document.createElement('div')
      div.classList.add(divClassName)
      const span = document.createElement('span')
      span.classList.add(spanClassName)
      const ul = document.createElement('ul')
      const li = document.createElement('li')
      li.innerHTML = notFound
      li.classList.add('form-inputSelect-data')
      span.innerHTML = this.directionArrowSVG
      const spanHeight = 21
      const spanWidth = 21
      span.style.position = 'absolute'
      span.style.display = 'none'
      span.style.justifyContent = 'center'
      span.style.alignItems = 'center'
      span.style.cursor = 'pointer'
      span.style.overflow = 'hidden'
      span.style.transition = 'all 0.2s'
      ul.style.width = ele[1].offsetWidth + 'px'
      ul.style.listStyle = 'none'
      div.style.position = 'absolute'
      div.style.display = 'none'
      ul.style.boxShadow = '0px 0px 5px -1px gray'
      li.style.display = 'none'
      css.style(ul, {
        backgroundColor: '#fff',
        borderRadius: '8px',
        marginTop: '5px',
        padding: '2px 5px',
        boxSizing: 'border-box'
      })
      div.appendChild(ul)
      ele[1].after(span)
      ele[1].after(div)
      let isRotate = false
      renderUL()
      function renderUL () {
        ul.innerHTML = ''
        for (const key in data) {
          ul.innerHTML += `<li class="form-inputSelect-data" data-value=${key}>${data[key]}</li>`
        }
        ul.appendChild(li)
        inputSelectLiListener()
      }
      function inputSelectLiListener () {
        const inputSelectLi = dqa(
          `.${divClassName} ul .form-inputSelect-data`
        )
        css.styles(inputSelectLi, {
          cursor: 'pointer',
          width: '100%',
          color: 'rgb(211, 211, 211)',
          textAlign: 'center'
        })
        AllListener(inputSelectLi, 'mouseover', item => {
          item.style.backgroundColor = '#f3f3f3'
          item.style.color = 'rgb(101, 101, 101)'
          item.style.borderRadius = '5px'
        })
        AllListener(inputSelectLi, 'mouseout', item => {
          item.style.backgroundColor = '#fff'
          item.style.color = 'rgb(211, 211, 211)'
        })
        AllListener(inputSelectLi, 'mousedown', item => {
          ele[1].value = item.innerText
          span.style.transform = 'rotate(0deg)'
          div.style.display = 'none'
          isRotate = false
          callback(item.dataset.value)
        })
      }
      ele[1].addEventListener('focus', () => {
        span.style.transform = 'rotate(180deg)'
        isRotate = true
        style()
      })
      ele[1].addEventListener('blur', () => {
        span.style.transform = 'rotate(0deg)'
        div.style.display = 'none'
        isRotate = false
      })
      span.addEventListener('click', () => {
        span.style.transform = isRotate
          ? 'rotate(0deg)'
          : 'rotate(180deg)'
        div.style.display = isRotate ? 'none' : 'flex'
        isRotate = !isRotate
      })
      Listener(ele[1], 'change', () => {
        if (limitation) {
          const value = ele[1].value
          let mate = false
          for (const key in data) {
            if (value === data[key]) {
              mate = true
              break
            }
          }
          if (!mate) {
            ele[1].value = ''
            dqa(`.${divClassName} ul .form-inputSelect-data`).forEach(
              item => {
                item.style.display = 'block'
              }
            )
            li.style.display = 'none'
          }
        }
      })
      Listener(ele[1], 'input', () => {
        li.style.display = 'none'
        let haveLi = false
        dqa(`.${divClassName} ul .form-inputSelect-data`).forEach(
          item => {
            if (ele[1].value === '' || ele[1].value === null) {
              item.style.display = 'block'
              haveLi = true
            } else {
              if (item.innerText.indexOf(ele[1].value) === -1) {
                item.style.display = 'none'
              } else {
                item.style.display = 'block'
                haveLi = true
              }
            }
          }
        )
        if (!haveLi) li.style.display = 'block'
        else li.style.display = 'none'
      })
      window.onresize = style()
      window.addEventListener('resize', () => style())
      function style () {
        span.style.display = 'flex'
        div.style.display = 'flex'
        span.style.height = spanHeight + 'px'
        span.style.width = spanWidth + 'px'
        span.style.top =
          ele[1].offsetTop +
          (ele[1].offsetHeight - spanHeight) / 2 +
          'px'
        span.style.left =
          ele[1].offsetLeft + ele[1].offsetWidth - spanWidth + 'px'
        ul.style.width = ele[1].offsetWidth + 'px'
        div.style.top = ele[1].offsetTop + ele[1].offsetHeight + 'px'
        div.style.left = ele[1].offsetLeft + 'px'
      }
      return span
    }
  }
}

/**
 * css样式类
 */
const css = {
  /**
   * 单个元素的样式设置
   * @param {CSS选择器或元素} element
   * @param {样式对象} styleList
   * @returns 元素
   */
  style: function (element, styleList = {}) {
    if (!(styleList instanceof Object)) {
      console.log('非对象!(第二个形参)：' + styleList)
      return
    }
    const ele = existElement(element, '未找到元素(css.style):')
    if (ele[0]) {
      let display = ele[1].style.display
      ele[1].style.display = 'none'
      for (const key in styleList) {
        ele[1].style[formKey(key)] = styleList[key]
        if (key === 'display') display = styleList[key]
      }
      ele[1].style.display = display
      function formKey (key = '') {
        if (!key.includes('-')) return key
        const index = key.indexOf('-')
        return (
          key.substring(0, index) +
          key.substring(index + 1, index + 2).toUpperCase() +
          key.substring(index + 2, key.length)
        )
      }
      return ele[1]
    }
  },
  /**
   * 多个同名元素的样式设置
   * @param {CSS选择器或元素伪数组} elements
   * @param {样式对象} styleList
   * @returns 元素伪数组
   */
  styles: function (elements, styleList = {}) {
    if (!(styleList instanceof Object)) {
      console.log('非对象!(第二个形参)：' + styleList)
      return
    }
    const ele = existElements(elements, '未找到元素(css.styles):')
    if (ele[0]) {
      try {
        ele[1].forEach(item => {
          for (const key in styleList) {
            item.style[formKey(key)] = styleList[key]
          }
        })
      } catch {
        for (const key in styleList) {
          ele[1].style[formKey(key)] = styleList[key]
        }
      }
      function formKey (key = '') {
        if (!key.includes('-')) return key
        const index = key.indexOf('-')
        return (
          key.substring(0, index) +
          key.substring(index + 1, index + 2).toUpperCase() +
          key.substring(index + 2, key.length)
        )
      }
      return ele[1]
    }
  },
  /**
   * 滚动条自定义样式设置
   * @param {滚动条背景样式} style Object
   * @param {滚动条轨道样式} style.track Object
   * @param {滚动条滑块样式} style.thumb Object
   */
  scrollbar: function (
    element = 'body',
    style = { track: {}, thumb: {} }
  ) {
    const ele = existElement(element, '未找到元素(css.scrollbar):')
    if (!ele[0]) return
    let css = '<style css-id="scroll">'
    if (style.track) {
      css += `${element}::-webkit-scrollbar-track {`
      for (const key in style.track) {
        if (key !== 'single-layer') {
          css += `${formStyle(key)}:${style.track[key]};`
        }
      }
      css += '}'
    }
    if (style.thumb) {
      css += `${element}::-webkit-scrollbar-thumb {`
      for (const key in style.thumb) {
        if (key !== 'single-layer') {
          css += `${formStyle(key)}:${style.thumb[key]};`
        }
      }
      css += '}'
    }
    let css2 = ''
    for (const key in style) {
      if (key !== 'single-layer') {
        if (key !== 'track' && key !== 'thumb') {
          !css2 && (css2 = `${element}::-webkit-scrollbar {`)
          css2 += `${formStyle(key)}:${style[key]};`
        }
      }
    }
    css2 && (css += css2 + '}')
    css += '</>'
    const scrollID = document.querySelector('[css-id="scroll]')
    const head = document.querySelector('head')
    scrollID && head.removeChild(scrollID)
    head.innerHTML += css
    function formStyle (styleKey) {
      if (!/[A-Z]+/.test(styleKey)) return styleKey
      return styleKey
        .split('')
        .map(item => {
          if (/[A-Z]+/.test(item)) return '-' + item.toLowerCase()
          return item
        })
        .join('')
    }
  },

  /**
   * css全局通用样式base。
   * 默认全局字体颜色：#333
   * 默认全局字体大小：14px
   * 默认body背景颜色：#fff
   * 默认a标签的href属性值为：javascript:;
   * @param {全局字体颜色} themeFontColors String
   * @param {全局字体大小} themeFontWeight String
   * @param {body背景颜色} bodyBackground String
   */
  base: function (
    themeFontColors = '#333',
    themeFontWeight = '14px',
    bodyBackground = '#fff'
  ) {
    const styleElementHTML = `
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    body {
      font-family:
        -apple-system,
        BlinkMacSystemFont,
        PingFangSC-Regular,
        "PingFang SC",
        "Microsoft YaHei",
        "Helvetica Neue",
        Helvetica,
        Arial,
        sans-serif;
      font-size: ${themeFontWeight};
      color: ${themeFontColors};
      background-color: ${bodyBackground};
    }
    ins,
    a {
      text-decoration: none;
      color: ${themeFontColors};
    }
    ol,
    ul {
      list-style: none;
    }
    i {
      font-style: normal;
    }
    input,textarea {
      border: none;
      background-color: unset;
      outline: unset;
    }
    `
    const styleElement = document.createElement('style')
    styleElement.innerHTML = styleElementHTML
    document.head.appendChild(styleElement)
    window.addEventListener('load', () => {
      const a = document.querySelectorAll('a')
      a.forEach(item => {
        item.href = 'javascript:;'
      })
    })
  }
}

/**
 * 单元素单事件绑定的简写形式
 * 类似检测按键的，可以在listeners中传入对象{事件类型：按键/鼠标按键}。
 * 对象封装的键盘检测有：keyCode、code、key；
 * 对象封装的鼠标检测有：button、buttons。
 * 如果有其他获取，e传入执行函数的第二个参数中
 * @param {绑定元素} element Element
 * @param {事件类型} listener String
 * @param {执行函数} executeFunction Function
 * @param {执行函数形参_事件对象} executeFunction_element Element
 * @param {执行函数形参_事件源} executeFunction_e
 */
function Listener (
  element,
  listener = '',
  executeFunction = function (e) {}
) {
  const ele = existElement(element, '未找到元素(Listener):')
  if (!ele[0]) return
  if (typeof listener === 'string') {
    ele[1].addEventListener(listener, function (e) {
      executeFunction.call(ele[1], ele[1], e)
    })
  } else {
    for (const key in listener) {
      ele[1].addEventListener(key, function (e) {
        if (e.keyCode === listener[key]) {
          executeFunction.call(ele[1], ele[1], e)
        } else if (e.code === listener[key]) {
          executeFunction.call(ele[1], ele[1], e)
        } else if (e.key === listener[key]) {
          executeFunction.call(ele[1], ele[1], e)
        } else if (e.button === listener[key]) {
          executeFunction.call(ele[1], ele[1], e)
        } else if (e.buttons === listener[key]) {
          executeFunction.call(ele[1], ele[1], e)
        }
      })
    }
  }
}
/**
 * 【单元素多事件绑定，执行同样的代码时使用】
 * 类似检测按键的，可以在listeners中传入对象{事件类型：按键/鼠标按键}。
 * 封装的键盘检测有：keyCode、code、key；
 * 封装的鼠标检测有：button、buttons。
 * 如果有其他获取，已将e传入执行函数的第二个参数中
 * @param {绑定元素} element Element
 * @param {事件类型数组} listeners StringArray
 * @param {执行函数} executeFunction Function
 * @param {执行函数形参_事件对象} executeFunction_element Element
 * @param {执行函数形参_事件源} executeFunction_e
 */
function Listeners (
  element,
  listeners = [],
  executeFunction = function (e) {}
) {
  const ele = existElement(element, '未找到元素(Listeners):')
  if (!ele[0]) return
  listeners.forEach(item => {
    if (typeof item === 'string') {
      ele[1].addEventListener(item, function (e) {
        executeFunction.call(ele[1], ele[1], e)
      })
    } else {
      for (const key in item) {
        ele[1].addEventListener(key, function (e) {
          if (e.keyCode === item[key]) {
            executeFunction.call(ele[1], ele[1], e)
          } else if (e.code === item[key]) {
            executeFunction.call(ele[1], ele[1], e)
          } else if (e.key === item[key]) {
            executeFunction.call(ele[1], ele[1], e)
          } else if (e.button === item[key]) {
            executeFunction.call(ele[1], ele[1], e)
          } else if (e.buttons === item[key]) {
            executeFunction.call(ele[1], ele[1], e)
          }
        })
      }
    }
  })
}

/**
 * 全部同名元素单事件绑定，执行同样的代码时使用
 * 类似检测按键的，可以在listener中传入对象{事件类型：按键/鼠标按键}。
 * 如果传入多个事件类型，只取第一个
 * 封装的键盘检测有：keyCode、code、key；
 * 封装的鼠标检测有：button、buttons。
 * 如果有其他获取，已将e传入执行函数的第二个参数中
 * @param {绑定同名元素} elements Element
 * @param {事件类型} listener String
 * @param {执行函数} executeFunction Function
 * @param {执行函数形参_事件对象} executeFunction_element Element
 * @param {执行函数形参_事件源} executeFunction_e
 */
function AllListener (
  elements,
  listener = '',
  executeFunction = function (e) {}
) {
  const ele = existElements(elements, '未找到元素(AllListener):')
  if (!ele[0]) return
  ele[1].forEach(item => {
    if (typeof listener === 'string') {
      item.addEventListener(listener, function (e) {
        executeFunction.call(item, item, e)
      })
    } else if (listener instanceof Object) {
      for (const key in listener) {
        item.addEventListener(key, function (e) {
          if (e.keyCode === listener[key]) {
            executeFunction.call(item, item, e)
          } else if (e.code === listener[key]) {
            executeFunction.call(item, item, e)
          } else if (e.key === listener[key]) {
            executeFunction.call(item, item, e)
          } else if (e.button === listener[key]) {
            executeFunction.call(item, item, e)
          } else if (e.buttons === listener[key]) {
            executeFunction.call(item, item, e)
          }
        })
      }
    }
  })
}

/**
 * 【多元素单事件绑定，执行同样的代码时使用】
 * 类似检测按键的，可以在listener中传入对象{事件类型：按键/鼠标按键}。
 * 如果传入多个事件类型，只取第一个
 * 封装的键盘检测有：keyCode、code、key；
 * 封装的鼠标检测有：button、buttons。
 * 如果有其他获取，已将e传入执行函数的第二个参数中
 * @param {绑定元素数组} elements ElementArray
 * @param {事件类型} listener String
 * @param {执行函数} executeFunction Function
 * @param {执行函数形参_事件对象} executeFunction_element Element
 * @param {执行函数形参_事件源} executeFunction_e
 */
function eventsListener (
  elements = [],
  listener = '',
  executeFunction = function (e) {}
) {
  elements.forEach(item => {
    const ele = existElement(item, '未找到元素(eventsListener):')
    if (ele[0]) {
      if (typeof listener === 'string') {
        ele[1].addEventListener(listener, function (e) {
          executeFunction.call(ele[1], ele[1], e)
        })
      } else if (listener instanceof Object) {
        for (const key in listener) {
          ele[1].addEventListener(key, function (e) {
            if (e.keyCode === listener[key]) {
              executeFunction.call(ele[1], ele[1], e)
            } else if (e.code === listener[key]) {
              executeFunction.call(ele[1], ele[1], e)
            } else if (e.key === listener[key]) {
              executeFunction.call(ele[1], ele[1], e)
            } else if (e.button === listener[key]) {
              executeFunction.call(ele[1], ele[1], e)
            } else if (e.buttons === listener[key]) {
              executeFunction.call(ele[1], ele[1], e)
            }
          })
        }
      }
    }
  })
}

/**
 * 元素内容渲染
 * @param {需要渲染内容的元素} element Element
 * @param {内容} content String
 * @param {是否覆盖渲染} cover Boolean
 * @returns 元素innerHTML内容
 */
function renderContent (
  element = '',
  content = '',
  cover = false
) {
  const ele = existElement(element, '未找到元素(renderContent):')
  if (ele[0]) {
    if (cover) {
      ele[1].innerHTML = content
    } else {
      ele[1].innerHTML += content
    }
    return ele[1].innerHTML
  }
}

/**
 * document.querySelector方法简写
 * @param {选择器或元素} element String
 * @returns element
 */
function dq (element = '') {
  const ele = existElement(
    element,
    '未找到元素(document.querySelector):'
  )
  if (ele[0]) return ele[1]
}
/**
 * document.querySelectorAll方法简写
 * @param {选择器或元素} elements String
 * @returns elements
 */
function dqa (elements = '') {
  const ele = existElements(
    elements,
    '未找到元素(document.querySelectorAll):'
  )
  if (ele[0]) return ele[1]
}

/**
 * 将对象拆分成一层结构，同名属性会自动在末尾加上序号排序
 * @param {多层对象} obj
 * @returns Object
 */
function singleLayer (obj = {}) {
  const tempObj = {}
  let num = 1
  singleFn(obj)
  function singleFn (obj) {
    for (const key in obj) {
      if (
        Object.prototype.toString.call(obj[key]) === '[object Object]'
      ) {
        singleFn(obj[key])
      } else {
        tempObj[key]
          ? (tempObj[key + '_' + ++num] = obj[key])
          : (tempObj[key] = obj[key])
      }
    }
  }
  return tempObj
}


/**
 * 本地持久化存储方法
 * 自动进行JSON转换
 */
const local = {
  /**
 * 魔法字符串
 */
  MagicString : "",
  /**
   * 将数据存储到本地
   * @param {属性名} dataName String
   * @param {属性值} data
   * @returns JSON||null
   */
  set: function (dataName, data) {
    if (Is.Undefined(data)) { 
      data = dataName
      dataName = this.MagicString
    }
    const type = Object.prototype.toString.call(dataName)
    if (!(type === '[object String]')) {
      console.error(
        '储存失败(local.set)：属性名格式不正确[需求：string]'
      )
      return null
    }
    if (data === '' || data === null || data === undefined) {
      console.error('储存失败(local.set)：请传入数据！')
      return null
    }
    try {
      localStorage.setItem(dataName, JSON.stringify(data))
      return JSON.stringify(data)
    } catch {
      console.error(
        '储存失败(local.set)：\n请检查浏览器是否拦截本地储存\n或使用服务器的方式存储'
      )
    }
  },
  /**
   * 获取本地存储数据，可传入执行函数直接处理，形参为数据
   * @param {属性名} dataName String
   * @param {获取成功后的执行函数} processingData Function
   * @param {执行函数形参_已格式化的数据} processingData_data Data
   * @returns data||null
   */
  get: function (dataName, processingData) {
    if (Is.Undefined(dataName)) { 
      processingData = dataName
      dataName = this.MagicString
    }
    if (localStorage.getItem(dataName)) {
      const data = JSON.parse(localStorage.getItem(dataName))
      if(Is.Function(processingData))processingData(data)
      return data
    } else {
      console.warn(
        '获取失败(getItem)：未找到属性名为 ' +
          dataName +
          ' 的本地存储数据！'
      )
      return null
    }
  },
  /**
   * 删除本地数据
   * @param {属性名} dataName String
   * @param {是否显示未找到数据的错误提示} errInfo Boolean
   * @returns Boolean
   */
  remove: function (dataName, errInfo = true) {
    if (Is.Undefined(dataName)) { 
      dataName = this.MagicString
    }
    if (Is.Boolean(dataName)) { 
      errInfo = dataName
      dataName = this.MagicString
    }
    if (localStorage.getItem(dataName)) {
      localStorage.removeItem(dataName)
      return true
    } else {
      errInfo &&
        console.warn(
          '删除失败(removeItem)：未找到属性名为 ' +
            dataName +
            ' 的本地存储数据！'
        )
      return false
    }
  },
  /**
   * 清空本地存储数据
   */
  clear: function () {
    localStorage.clear()
  }
}
/**
 * 魔法字符串
 */
let __YHBToolSessionMagicString = ""
/**
 * 本地临时存储方法
 * 自动进行JSON转换
 */
const session = {
  /**
   * 设置魔法字符串
   * @param {字符串名} str 
   */
  setMagicString: function (str = '') {
    __YHBToolSessionMagicString = str
  },
  /**
   * 本地临时数据储存
   * @param {属性名} dataName String
   * @param {属性值} data
   * @returns JSON||null
   */
  set: function (dataName, data) {
    if (Is.Undefined(data)) { 
      data = dataName
      dataName = __YHBToolSessionMagicString
    }
    const type = Object.prototype.toString.call(dataName)
    if (!(type === '[object String]')) {
      console.error(
        '储存失败(setItem)：属性名格式不正确[需求：string]'
      )
      return null
    }
    if (data === '' || data === null || data === undefined) {
      console.error('储存失败(setItem)：请传入数据！')
      return null
    }
    try {
      sessionStorage.setItem(dataName, JSON.stringify(data))
      return JSON.stringify(data)
    } catch {
      console.error(
        '储存失败(session.set)：\n请检查浏览器是否拦截本地储存\n或使用服务器的方式存储'
      )
    }
  },
  /**
   * 获取本地存储数据，可传入执行函数直接处理，形参为数据
   * @param {属性名} dataName String
   * @param {获取成功后的执行函数} processingData Function
   * @param {执行函数形参_已格式化的数据} processingData_data Data
   * @returns data||null
   */
  get: function (dataName, processingData) {
    if (Is.Undefined(dataName)) { 
      processingData = dataName
      dataName = __YHBToolSessionMagicString
    }
    if (sessionStorage.getItem(dataName)) {
      const data = JSON.parse(sessionStorage.getItem(dataName))
      if(Is.Function(processingData)) processingData(data)
      return data
    } else {
      console.warn(
        '获取失败(getItem)：未找到属性名为 ' +
          dataName +
          ' 的本地存储数据！'
      )
      return null
    }
  },
  /**
   * 删除本地数据
   * @param {属性名} dataName String
   * @param {是否显示未找到数据的错误提示} errInfo Boolean
   * @returns Boolean
   */
  remove: function (dataName, errInfo = true) {
    if (Is.Undefined(dataName)) { 
      dataName = __YHBToolSessionMagicString
    }
    if (Is.Boolean(dataName)) { 
      errInfo = dataName
      dataName = __YHBToolSessionMagicString
    }
    if (sessionStorage.getItem(dataName)) {
      sessionStorage.removeItem(dataName)
      return true
    } else {
      errInfo &&
        console.warn(
          '删除失败(removeItem)：未找到属性名为 ' +
            dataName +
            ' 的本地存储数据！'
        )
      return false
    }
  },
  /**
   * 清空本地存储数据
   */
  clear: function () {
    sessionStorage.clear()
  }
}
/**
 * 魔法字符串
 */
let __YHBToolCookieMagicString = ""
/**
 * 本地临时存储方法
 * 自动进行JSON转换
 */
const cookie = {
  /**
   * 设置魔法字符串
   * @param {字符串名} str 
   */
  setMagicString: function (str = '') {
    __YHBToolCookieMagicString = str
  },
  /**
   * 本地cookie数据储存
   * @param {属性名} dataName String
   * @param {属性值} data
   * @returns null
   */
  set: function (dataName, data) {
    if (Is.Undefined(data)) { 
      data = dataName
      dataName = __YHBToolCookieMagicString
    }
    const type = Object.prototype.toString.call(dataName)
    if (!(type === '[object String]')) {
      console.error(
        '储存失败(cookie.set)：属性名格式不正确[需求：string]'
      )
      return null
    }
    try {
      document.cookie = dataName + '=' + data
      const temp = {}
      temp[dataName] = data
      return temp
    } catch {
      console.error(
        '储存失败(cookie.set)：\n请检查浏览器是否拦截本地cookie储存'
      )
    }
  },
  /**
   * 获取cookie存储数据，自动处理为对象
   * @param {属性名_可选_不写默认返回全部对象} dataName String
   * @returns data||null
   */
  get: function (dataName) {
    if(Is.Undefined(dataName))dataName = __YHBToolCookieMagicString
    const cookieData = document.cookie.split('; ')
    const cookieObj = {}
    cookieData.forEach(item => {
      cookieObj[item.substring(0, item.indexOf('='))] =
        item.substring(item.indexOf('=') + 1, item.length)
    })
    if (dataName) {
      if (cookieObj[dataName]) return cookieObj[dataName]
      else {
        console.warn(
          '获取失败(cookie.get)：未找到属性名为 ' +
            dataName +
            ' 的本地cookie存储数据！'
        )
        return null
      }
    } else {
      return cookieObj
    }
  },
  /**
   * 删除本地cookie数据
   * @param {属性名} dataName String
   * @param {是否显示未找到数据的错误提示} errInfo Boolean
   * @returns Boolean
   */
  remove: function (dataName, errInfo = true) {
    if (Is.Undefined(dataName)) { 
      dataName = __YHBToolCookieMagicString
    }
    if (Is.Boolean(dataName)) { 
      errInfo = dataName
      dataName = __YHBToolCookieMagicString
    }
    try {
      document.cookie =
        dataName + '=;expires=Thu, 01 Jan 1970 00:00:00 GMT'
      return true
    } catch (error) {
      errInfo &&
        console.warn(
          '删除失败(cookie.remove)：未找到属性名为 ' +
            dataName +
            ' 的本地cookie存储数据！'
        )
      return false
    }
  },
  /**
   * 清空本地cookie存储数据
   */
  clear: function () {
    for (const key in this.get()) {
      this.remove(key)
    }
  }
}

/**
 * 跳转至目标URL
 * @param {目标URL} url
 */
function toUrl (url = '') {
  location.href = url
}

/**
 * 映射表构造函数
 * @param {映射表对象} Table Object
 */
class MapTable {
  constructor (Table = {}) {
    this.Table = Table
  }

  /**
   * 查询映射表中是否存在某个key/value
   * @param {任意值} anyKey
   * @returns Boolean
   */
  seek (anyKey) {
    for (const key in this.Table) {
      if (key === anyKey) return true
      if (this.Table[key] === anyKey) return true
    }
    return false
  }

  /**
   * 查询映射表中是否存在某个value
   * @param {任意值} anyValue
   * @returns Boolean
   */
  seekValue (anyValue) {
    for (const key in this.Table) {
      if (this.Table[key] === anyValue) return true
    }
    return false
  }

  /**
   * 查询映射表中是否存在某个key
   * @param {任意值} anyKey
   * @returns Boolean
   */
  seekKey (anyKey) {
    for (const key in this.Table) {
      if (key === anyKey) return true
    }
    return false
  }

  /**
   * 返回映射表的对应key/value
   * @param {任意值} any
   * @returns key/value
   */
  shine (any) {
    for (const key in this.Table) {
      if (key === any) return this.Table[key]
      if (this.Table[key] === any) return key
    }
  }

  /**
   * 根据key返回映射表的对应value
   * @param {任意值} anyKey
   * @returns value
   */
  shineToValue (anyKey) {
    for (const key in this.Table) {
      if (key === anyKey) return this.Table[key]
    }
  }

  /**
   * 根据value返回映射表的对应key
   * @param {任意值} anyValue
   * @returns key
   */
  shineToKey (anyValue) {
    for (const key in this.Table) {
      if (this.Table[key] === anyValue) return key
    }
  }

  /**
   * 往映射表中添加键值对
   * @param {对应对象} mapObj
   */
  add (mapObj) {
    for (const key in mapObj) {
      this.Table[key] = mapObj[key]
    }
  }

  /**
   * 根据key，将value修改掉
   * @param {对应对象} obj 
   */
  adjustValue(obj = {}) { 
    for (const key in this.Table) {
      for (const insideKey in obj) {
        if (key === insideKey) { 
          this.Table[key]=obj[insideKey]
        }
      }
    }
  }

  /**
   * 根据value将key修改掉
   * @param {对应对象} obj 
   */
  adjustKey(obj = {}) { 
    for (const key in this.Table) {
      const value = this.Table[key]
      for (const insideKey in obj) {
        if (value === obj[insideKey]) { 
          this.del(key)
          this.Table[insideKey] = obj[insideKey]
        }
      }
    }
  }

  /**
   * 删除映射表中的键值对，可传入key或value
   * @param {任意值} anyKey
   * @returns Object
   */
  del (anyKey) {
    for (const key in this.Table) {
      if (key === anyKey) {
        const temp = {}
        temp[anyKey] = this.Table[anyKey]
        delete this.Table[anyKey]
        return temp
      }
      if (this.Table[key] === anyKey) {
        const temp = {}
        temp[key] = this.Table[key]
        delete this.Table[key]
        return temp
      }
    }
  }
}

/**
 * 获取指定长度的随机字符串
 * @param {长度} length Number
 * @param {是否开启特殊字符} special Boolean
 * @param {自定义特殊字符_可选} specialChar Array
 * @returns String
 */
function randomToken (
  length = 8,
  special = false,
  specialChar = []
) {
  let token = ''
  for (let i = 0; i < length; i++) {
    const typeNum = Digit.randomInt(0, special ? 3 : 2, true)
    typeNum === 0 && (token += Digit.randomInt(0, 9, true))
    typeNum === 1 && (token += randomChar(charArr.Lowercase))
    typeNum === 2 && (token += randomChar(charArr.Uppercase))
    typeNum === 3 &&
      (token += randomChar(
        specialChar.length ? specialChar : charArr.SpecialChar
      ))
  }
  function randomChar (char = []) {
    return char[Digit.randomInt(0, char.length, false)]
  }
  return token
}

/**
 * 用来储存常用字符
 */
const charArr = {
  /**
   * 小写字母
   */
  Lowercase: [
    'a',
    'b',
    'c',
    'd',
    'e',
    'f',
    'g',
    'h',
    'i',
    'j',
    'k',
    'l',
    'm',
    'n',
    'o',
    'p',
    'q',
    'r',
    's',
    't',
    'u',
    'v',
    'w',
    'x',
    'y',
    'z'
  ],
  /**
   * 大写字母
   */
  Uppercase: [
    'A',
    'B',
    'C',
    'D',
    'E',
    'F',
    'G',
    'H',
    'I',
    'J',
    'K',
    'L',
    'M',
    'N',
    'O',
    'P',
    'Q',
    'R',
    'S',
    'T',
    'U',
    'V',
    'W',
    'X',
    'Y',
    'Z'
  ],
  /**
   * 数字
   */
  Number: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
  /**
   * 字符数字
   */
  NumberChar: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
  /**
   * 特殊字符
   */
  SpecialChar: [
    '!',
    '@',
    '%',
    '&',
    '$',
    '_',
    '#',
    '^',
    '?',
    '+',
    '-',
    '*',
    '/',
    '=',
    '.'
  ]
}

/**
 * 元素是否存在
 * @param {元素或元素的css选择器} element String
 * @param {错误信息} errMsg
 * @returns [Boolean,element||null]
 */
function existElement (element, errMsg = '未找到元素:') {
  const elementStr = element
  const segment = __YHBToolIsFloatHTML ? '<br/>' : '\n'
  if (
    elementStr === '' ||
    elementStr === null ||
    elementStr === undefined
  ) {
    errMsg =
      errMsg +
      `${segment}DOM异常，未检测到页面元素！${segment}您的参数传递为空值！${segment}${segment}解决：${segment}请检查元素选择器是否书写正确${segment}或检查传入的元素是否存在！`
  } else {
    errMsg =
      errMsg +
      `${segment}DOM异常，未检测到页面元素！${segment}您的参数传递为（${elementStr}）${segment}${
        typeof elementStr === 'string'
          ? segment +
            '您的选择器分析如下：' +
            segment +
            _selectorAnalysis(elementStr) +
            segment
          : ''
      }${segment}解决：${segment}请检查元素选择器是否书写正确${segment}或检查传入的元素是否存在！`
  }

  try {
    element =
      typeof element === 'string'
        ? element === 'window'
          ? window
          : document.querySelector(element)
        : element
    if (element) return [true, element]
    else {
      console.error(errMsg)
      return [false, null]
    }
  } catch (e) {
    console.error(errMsg)
    return [false, null]
  }
}
/**
 * 元素是否存在
 * @param {元素伪数组或元素的css选择器} elements String
 * @param {错误信息} errMsg
 * @returns [Boolean,elements||null]
 */
function existElements (elements, errMsg = '未找到元素:') {
  const elementsStr = elements
  const segment = __YHBToolIsFloatHTML ? '<br/>' : '\n'
  if (
    elementsStr === '' ||
    elementsStr === null ||
    elementsStr === undefined
  ) {
    errMsg =
      errMsg +
      `${segment}DOM异常，未检测到页面元素！${segment}您的参数传递为空值！${segment}${segment}解决：${segment}请检查元素选择器是否书写正确${segment}或检查传入的元素是否存在！`
  } else {
    errMsg =
      errMsg +
      `${segment}DOM异常，未检测到页面元素！${segment}您的参数传递为（${elementsStr}）${segment}${
        typeof elementsStr === 'string'
          ? segment +
            '您的选择器分析如下：' +
            segment +
            _selectorAnalysis(elementsStr) +
            segment
          : ''
      }${segment}解决：${segment}请检查元素选择器是否书写正确${segment}或检查传入的元素是否存在！`
  }
  try {
    elements =
      typeof elements === 'string'
        ? elements === 'window'
          ? window
          : document.querySelectorAll(elements)
        : elements
    if (elementsStr === 'window' || elements.length !== 0) {
      return [true, elements]
    } else {
      console.error(errMsg)
      return [false, null]
    }
  } catch {
    console.error(errMsg)
    return [false, null]
  }
}

/**
 * 解构分析选择器
 * @param {选择器} selector String
 * @returns String
 */
function _selectorAnalysis (selector = '') {
  const segment = __YHBToolIsFloatHTML ? '<br/>' : '\n'
  let str = ''
  selector = Str.removeSpace(selector)
  if (selector.indexOf(' ') !== -1) {
    str += '元素结构为：' + segment
    Str.subChar(selector, ' ').forEach((item, index) => {
      str += index + 1 + '. '
      for (let i = 0; i < index; i++) {
        str += '    '
      }
      str += `${_selectorAnalysis(item)}${segment}`
    })
  } else {
    selector.split('').forEach(item => {
      if (item === '.') str += ',且class属性为'
      else if (item === '#') str += ',且id属性为'
      else if (item === '[') str += ',且name属性为'
      else if (item === '=' || item === ']') str += ''
      else str += item
    })
    if (str.substring(0, 2) === ',且') {
      str = str.substring(2, str.length)
    } else {
      str = '标签为' + str
    }
    str += '的元素'
  }
  return str
}

/**
 * 模块类
 */
const Module = {
  /**
   * 创建一个滑块
   * @param {执行函数} callback
   * @param {滑块当前百分比_没有%符号} callback_percentage Number
   */
  sliding: function (callback = function (percentage) {}) {
    const out = document.createElement('div')
    const back = document.createElement('div')
    const inner = document.createElement('div')
    const innerBack = document.createElement('div')
    const slider = document.createElement('div')

    inner.appendChild(slider)
    back.appendChild(innerBack)
    back.appendChild(inner)
    out.appendChild(back)

    css.style(out, {
      width: '20px',
      height: '150px',
      backgroundColor: '#bebebe',
      borderRadius: '1000PX',
      position: 'absolute',
      top: 0,
      let: 0
    })
    css.style(back, {
      width: '100%',
      height: '100%',
      position: 'relative',
      display: 'flex',
      justifyContent: 'center',
      alignItems: 'center'
    })
    css.style(innerBack, {
      position: 'absolute',
      width: '5px',
      height: '141px',
      backgroundColor: 'rgb(197, 197, 197)',
      borderRadius: '1000px',
      zIndex: 0
    })
    css.style(inner, {
      position: 'absolute',
      // top: "3%",
      bottom: '3%',
      width: '5px',
      height: '141px',
      backgroundColor: 'rgb(82, 82, 82)',
      borderRadius: '1000px',
      zIndex: 1
    })
    css.style(slider, {
      position: 'absolute',
      left: '-50%',
      width: '10px',
      height: '10px',
      backgroundColor: 'rgb(225, 65, 217)',
      borderRadius: '50%',
      cursor: 'pointer'
    })

    document.body.append(out)
    sliderDrag()
    function sliderDrag () {
      slider.onmousedown = function (e) {
        const boxTop = e.offsetY
        document.onmousemove = function (e) {
          let client = e.clientY + boxTop
          if (client <= 0) client = 0
          else if (client >= 131) client = 131
          slider.style.top = client + 'px'
          callback(parseInt((client / 131) * 100))
        }
        document.onmouseup = function () {
          document.onmousemove = null
        }
      }
    }

    back.onmousedown = function (e) {
      if (e.target === slider) return
      const boxLeft = e.offsetX
      const boxTop = e.offsetY
      document.onmousemove = function (e) {
        out.style.left = e.clientX - boxLeft + 'px'
        out.style.top = e.clientY - boxTop + 'px'
      }
      document.onmouseup = function () {
        document.onmousemove = null
      }
    }
  },
  /**
   * 创建一个徽章元素
   * 返回元素的HTML，请使用innerHTML来将此元素加载进去
   * @param {左侧文字} leftText String
   * @param {右侧文字} rightText String
   * @param {左侧背景色} leftColor String
   * @param {右侧背景色} rightColor String
   * @param {左侧文字颜色} leftTextColor String
   * @param {右侧文字颜色} rightTextColor String
   * @returns 徽章元素的HTML String
   */
  badge: function (
    leftText = '',
    rightText = '',
    leftColor = '',
    rightColor = '',
    leftTextColor = '',
    rightTextColor = ''
  ) {
    const span = document.createElement('span')
    span.classList.add('__YHBToolBadgeSpan')
    const leftSpan = document.createElement('span')
    const rightSpan = document.createElement('span')
    leftSpan.innerHTML = leftText
    rightSpan.innerHTML = rightText
    leftSpan.style.backgroundColor = leftColor || '#565656'
    rightSpan.style.backgroundColor = rightColor || '#41bc13'
    leftSpan.style.color = leftTextColor || '#fff'
    rightSpan.style.color = rightTextColor || '#fff'
    css.style(span, {
      borderRadius: '5px',
      overflow: 'hidden'
    })
    css.style(leftSpan, {
      textAlign: 'center',
      fontSize: '13px',
      borderRadius: '5px 0px 0px 5px',
      padding: '1px 3px 1px 7px',
      textShadow: '0.5px 0.5px 1px #000000a3'
    })
    css.style(rightSpan, {
      textAlign: 'center',
      fontSize: '13px',
      borderRadius: '0px 5px 5px 0px',
      padding: '1px 7px 1px 3px',
      textShadow: '0.5px 0.5px 1px #000000a3'
    })
    span.appendChild(leftSpan)
    span.appendChild(rightSpan)
    return span.outerHTML
  },
  /**
   * CSS基础样式调试台
   * @param {元素或元素的css选择器} element
   * @returns
   */
  styleDebugConsole: function (element = '') {
    const ele = existElement(
      element,
      '未找到元素(Module.styleDebugConsole):'
    )
    if (!ele[0]) return
    const div = document.createElement('div')
    const divHead = document.createElement('divHead')
    div.classList.add('__YHBToolStyleDebugConsole')
    divHead.classList.add('__YHBToolStyleDebugConsole-divHead')
    div.innerHTML = `
    <svg t="1696133302365" class="__YHBToolStyleDebugConsole-icon-svg" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4012" width="200" height="200"><path d="M325.456471 862.280661" fill="#1296db" p-id="4013"></path><path d="M882.057788 862.280661" fill="#1296db" p-id="4014"></path><path d="M236.028491 877.160382" fill="#1296db" p-id="4015"></path><path d="M960.132455 877.160382" fill="#1296db" p-id="4016"></path><path d="M63.683483 788.736998" fill="#1296db" p-id="4017"></path><path d="M958.469023 788.736998" fill="#1296db" p-id="4018"></path><path d="M64.77753 858.792098" fill="#1296db" p-id="4019"></path><path d="M163.396533 289.168875c-40.577772 0-66.525252 54.184545-35.441258 85.258218L477.217578 723.704878c20.031716 20.031716 49.823841 20.031716 69.853837 0l349.274345-349.277785c30.304744-30.294423 6.677812-85.258218-34.928639-85.258218L163.396533 289.168875 163.396533 289.168875z" fill="#1296db" p-id="4020"></path><path d="M959.523505 858.792098" fill="#1296db" p-id="4021"></path></svg>
    <div class="__YHBToolStyleDebugConsole-header">
      <h4>CSS基础样式调试台</h4>
      <h5>当前选择元素：<span id="__YHBToolStyleDebugConsole-header-ele">${element}</span></h5>
    </div>
    <form class="__YHBToolStyleDebugConsole-body" id="__YHBToolStyleDebugConsole-form">
        <div class="one">
          <label>
            display:
            <select onchange='_change("${element}","display")' name="display" id="__YHBToolStyleDebugConsole-body-display">
              <option value="0">请选择</option>
              <option value="block">block</option>
              <option value="inline">inline</option>
              <option value="inline-block">inline-block</option>
              <option value="flex">flex</option>
              <option value="table">table</option>
              <option value="none">none</option>
            </select>
          </label>
          <label>
            justify-content:
            <select onchange='_change("${element}","justify-content")' name="justify-content" id="__YHBToolStyleDebugConsole-body-justify-content">
              <option value="0">请选择</option>
              <option value="space-around">space-around</option>
              <option value="space-between">space-between</option>
              <option value="space-evenly">space-evenly</option>
              <option value="center">center</option>
              <option value="flex-start">flex-start</option>
              <option value="flex-end">flex-end</option>
            </select>
          </label>
          <label>
            align-items:
            <select onchange='_change("${element}","align-items")' name="align-items" id="__YHBToolStyleDebugConsole-body-align-items">
              <option value="0">请选择</option>
              <option value="space-around">center</option>
              <option value="stretch">stretch</option>
              <option value="flex-start">flex-start</option>
              <option value="flex-end">flex-end</option>
            </select>
          </label>
          <label>
            flex-direction:
            <select onchange='_change("${element}","flex-direction")' name="flex-direction" id="__YHBToolStyleDebugConsole-body-flex-direction">
              <option value="0">请选择</option>
              <option value="column">column</option>
              <option value="column-reverse">column-reverse</option>
              <option value="row">row</option>
              <option value="row-reverse">row-reverse</option>
            </select>
          </label>
          <label>
            flex-wrap:
            <select onchange='_change("${element}","flex-wrap")' name="flex-wrap" id="__YHBToolStyleDebugConsole-body-flex-wrap">
              <option value="0">请选择</option>
              <option value="nowrap">nowrap</option>
              <option value="wrap">wrap</option>
              <option value="wrap-reverse">wrap-reverse</option>
            </select>
          </label>
          <label>
            position:
            <select onchange='_change("${element}","position")' name="position" id="__YHBToolStyleDebugConsole-body-position">
              <option value="0">请选择</option>
              <option value="absolute">absolute</option>
              <option value="relative">relative</option>
              <option value="fixed">fixed</option>
            </select>
          </label>
          <label>
            text-align:
            <select onchange='_change("${element}","text-align")' name="text-align" id="__YHBToolStyleDebugConsole-body-text-align">
              <option value="0">请选择</option>
              <option value="center">center</option>
              <option value="left">left</option>
              <option value="right">right</option>
              <option value="fixed">fixed</option>
            </select>
          </label>
          <label>
            box-sizing:
            <select onchange='_change("${element}","box-sizing")' name="box-sizing" id="__YHBToolStyleDebugConsole-body-box-sizing">
              <option value="0">请选择</option>
              <option value="border-box">border-box</option>
              <option value="content-box">content-box</option>
            </select>
          </label>
          <label>
            overflow:
            <select onchange='_change("${element}","overflow")' name="overflow" id="__YHBToolStyleDebugConsole-body-overflow">
              <option value="0">请选择</option>
              <option value="auto">auto</option>
              <option value="hidden">hidden</option>
              <option value="scroll">scroll</option>
              <option value="visible">visible</option>
            </select>
          </label>
        </div>
        <div class="two">
          <div>
            <label>
              height:
              <input style="border: none;border-radius:3px;background-color:#d8dee9;" onchange='_change("${element}","height")' name="height" type="text" id="__YHBToolStyleDebugConsole-body-top" placeholder="高度" />
            </label>
            <label>
              width:
              <input style="border: none;border-radius:3px;background-color:#d8dee9;" onchange='_change("${element}","width")' name="width" type="text" id="__YHBToolStyleDebugConsole-body-top" placeholder="宽度" />
            </label>
          </div>
          <div>
            <label>
              top:
              <input style="border: none;border-radius:3px;background-color:#d8dee9;" onchange='_change("${element}","top")' name="top" type="text" id="__YHBToolStyleDebugConsole-body-top" placeholder="上距离" />
            </label>
            <label>
              right:
              <input style="border: none;border-radius:3px;background-color:#d8dee9;" onchange='_change("${element}","right")' name="right" type="text" id="__YHBToolStyleDebugConsole-body-right" placeholder="右距离" />
            </label>
            <label>
              bottom:
              <input style="border: none;border-radius:3px;background-color:#d8dee9;" onchange='_change("${element}","bottom")' name="bottom" type="text" id="__YHBToolStyleDebugConsole-body-bottom" placeholder="底距离" />
            </label>
            <label>
              left:
              <input style="border: none;border-radius:3px;background-color:#d8dee9;" onchange='_change("${element}","left")' name="left" type="text" id="__YHBToolStyleDebugConsole-body-left" placeholder="左距离" />
            </label>
          </div>
          <div>
            <label>
              margin:
              <input style="border: none;border-radius:3px;background-color:#d8dee9;" onchange='_change("${element}" "margin")' name="margin" type="text" id="__YHBToolStyleDebugConsole-body-margin" placeholder="外边距" />
            </label>
            <label>
              padding:
              <input style="border: none;border-radius:3px;background-color:#d8dee9;" onchange='_change("${element}","padding")' name="padding" type="text" id="__YHBToolStyleDebugConsole-body-margin" placeholder="内边距" />
            </label>
          </div>
          <div>
            <label>
              cursor:
              <select onchange='_change("${element}","cursor")' name="cursor" id="__YHBToolStyleDebugConsole-body-cursor">
                <option value="0">请选择</option>
                <option value="default">default</option>
                <option value="auto">auto</option>
                <option value="pointer">pointer</option>
                <option value="text">text</option>
                <option value="move">move</option>
                <option value="grab">grab</option>
                <option value="wait">wait</option>
                <option value="help">help</option>
              </select>
            </label>
            <label>
              transition:
              <input style="border: none;border-radius:3px;background-color:#d8dee9;" onchange='_change("${element}","transition")' name="transition" type="text" id="__YHBToolStyleDebugConsole-body-transition" placeholder="过渡" />
            </label>
          </div>
          <div>
            <label>
              transform:
              <select onchange='_transformChange("${element}")' name="transformType"     id="__YHBToolStyleDebugConsole-body-transform-type">
                <option value="0">请选择</option>
                <option value="translate">translate</option>
                <option value="translateX">translateX</option>
                <option value="translateY">translateY</option>
                <option value="rotate">rotate</option>
                <option value="scale">scale</option>
                <option value="skew">skew</option>
              </select>
              <input style="border: none;border-radius:3px;background-color:#d8dee9;" onchange='_transformChange("${element}","transformData")' name="transformData" type="text" id="__YHBToolStyleDebugConsole-body-margin" placeholder="" />
            </label>
          </div>
        </div>
        <div class="tree">
          <div>
            <label>
              background-color:
              <input style="border: none;border-radius:3px;background-color:#d8dee9;" onchange='_change("${element}","background-color")' name="background-color" type="text" id="__YHBToolStyleDebugConsole-body-background-color"
                placeholder="背景色" />
            </label>
            <label>
              color:
              <input style="border: none;border-radius:3px;background-color:#d8dee9;" onchange='_change("${element}","color")' name="color" type="text" id="__YHBToolStyleDebugConsole-body-color" placeholder="文字颜色" />
            </label>
          </div>
          <div>
            <label>
              font-size:
              <input style="border: none;border-radius:3px;background-color:#d8dee9;" onchange='_change("${element}","font-size")' name="font-size" type="text" id="__YHBToolStyleDebugConsole-body-font-size"
                placeholder="字体大小" />
            </label>
            <label>
              line-height:
              <input style="border: none;border-radius:3px;background-color:#d8dee9;" onchange='_change("${element}","line-height")' name="line-height" type="text" id="__YHBToolStyleDebugConsole-body-line-height"
                placeholder="行高" />
            </label>
            <label>
              font-weight:
              <input style="border: none;border-radius:3px;background-color:#d8dee9;" onchange='_change("${element}","font-weight")' name="font-weight" type="text" id="__YHBToolStyleDebugConsole-body-font-weight"
                placeholder="字体粗细" />
            </label>
          </div>
          <div>
            <label>
              border-radius:
              <input style="border: none;border-radius:3px;background-color:#d8dee9;" onchange='_change("${element}","border-radius")' name="border-radius" type="text" id="__YHBToolStyleDebugConsole-body-border-radius"
                placeholder="曲率" />
            </label>
            <label>
              border:
              <input style="border: none;border-radius:3px;background-color:#d8dee9;" onchange='_borderChange("${element}")' name="borderPx" type="text" id="__YHBToolStyleDebugConsole-body-border-px" placeholder="*宽度" />
              <select onchange='_borderChange("${element}")' name="borderType" id="__YHBToolStyleDebugConsole-body-border-type">
                <option value="0">请选择</option>
                <option value="solid">solid</option>
                <option value="double">double</option>
                <option value="dotted">dotted</option>
                <option value="dashed">dashed</option>
              </select>
              <input style="border: none;border-radius:3px;background-color:#d8dee9;" onchange='_borderChange("${element}")' name="borderColor" type="text" id="__YHBToolStyleDebugConsole-body-border-color"
                placeholder="颜色" />
            </label>
          </div>
        </div>
        <button>复制CSS样式</button>
        </form>
    `
    div.appendChild(divHead)
    document.body.prepend(div)
    let isSVG = false
    const header = document.querySelector(
      '.__YHBToolStyleDebugConsole-header'
    )
    const body = document.querySelector(
      '.__YHBToolStyleDebugConsole-body'
    )
    Listener(
      '.__YHBToolStyleDebugConsole-icon-svg',
      'click',
      item => {
        if (isSVG) {
          item.style.transform = 'rotate(0deg)'
          item.style.top = '10px'
          header.style.display = 'block'
          body.style.display = 'flex'
          div.style.height = '350px'
        } else {
          item.style.transform = 'rotate(180deg)'
          item.style.top = '-3px'
          div.style.height = '0'
          header.style.display = 'none'
          body.style.display = 'none'
        }
        isSVG = !isSVG
      }
    )
    div.onmousedown = function (e) {
      if (
        e.target.className === '__YHBToolStyleDebugConsole-divHead'
      ) {
        const boxLeft = e.offsetX
        const boxTop = e.offsetY
        document.onmousemove = function (e) {
          div.style.transform = ''
          div.style.left = e.clientX - boxLeft + 'px'
          div.style.top = e.clientY - boxTop + 'px'
        }
        document.onmouseup = function () {
          document.onmousemove = null
        }
      }
    }
    css.style(div, {
      width: window.innerWidth * 0.8 + 'px',
      height: '350px',
      borderRadius: '20px',
      backgroundColor: 'rgba(64, 64, 64, 0.7)',
      position: 'fixed',
      bottom: '10px',
      left: '50%',
      transform: 'translateX(-50%)',
      boxSizing: 'border-box',
      overflow: 'hidden',
      padding: '10px',
      zIndex: '9999999999999999999999999999999999'
    })
    css.style(divHead, {
      width: '100%',
      height: '50px',
      backgroundColor: 'rgba(0,0,0,0)',
      position: 'absolute',
      top: 0,
      zIndex: 0,
      left: 0
    })
    css.style('.__YHBToolStyleDebugConsole-icon-svg', {
      width: '25px',
      height: '25px',
      position: 'absolute',
      top: '10px',
      left: '20px',
      cursor: 'pointer',
      zIndex: '1',
      display: 'block'
    })
    css.style(header, {
      width: '100%',
      marginBottom: '10px',
      paddingBottom: '10px',
      textAlign: 'center',
      borderBottom: '2px dotted rgb(240, 240, 240)',
      position: 'relative'
    })
    css.style('.__YHBToolStyleDebugConsole-header h4', {
      color: '#00db04',
      fontSize: '18px',
      margin: 0
    })
    css.style('.__YHBToolStyleDebugConsole-header h5', {
      margin: 0,
      position: 'absolute',
      top: '50%',
      transform: 'translateY(-50%)',
      right: '10px',
      color: '#ffea00',
      fontsize: '14px'
    })
    css.style('.__YHBToolStyleDebugConsole-body', {
      display: 'flex',
      justifyContent: 'space-between',
      alignItems: 'flex-start',
      height: '100%',
      color: 'aquamarine'
    })
    css.style('.__YHBToolStyleDebugConsole-body .one', {
      borderRadius: '10px',
      display: 'flex',
      justifyContent: 'space-between',
      alignItems: 'center',
      flexWrap: 'wrap',
      width: '250px',
      height: '80%',
      backgroundColor: 'rgba(64, 64, 64, 0.7)',
      padding: '10px',
      marginLeft: '5px',
      fontSize: '13px'
    })
    css.style('.__YHBToolStyleDebugConsole-body .two', {
      borderRadius: '10px',
      display: 'flex',
      justifyContent: 'space-between',
      alignItems: 'center',
      flexWrap: 'wrap',
      width: '250px',
      height: '80%',
      backgroundColor: 'rgba(64, 64, 64, 0.7)',
      padding: '10px',
      marginLeft: '5px',
      fontSize: '13px',
      flex: 1
    })
    css.style('.__YHBToolStyleDebugConsole-body .tree', {
      borderRadius: '10px',
      display: 'flex',
      justifyContent: 'space-between',
      alignItems: 'center',
      flexWrap: 'wrap',
      width: '250px',
      height: '80%',
      backgroundColor: 'rgba(64, 64, 64, 0.7)',
      padding: '10px',
      marginLeft: '5px',
      fontSize: '13px',
      flex: 1
    })
    css.styles('.__YHBToolStyleDebugConsole-body .two div', {
      width: '100%',
      display: 'flex',
      justifyContent: 'center',
      alignItems: 'center'
    })
    css.styles('.__YHBToolStyleDebugConsole-body .tree div', {
      width: '100%',
      display: 'flex',
      justifyContent: 'center',
      alignItems: 'center'
    })
    css.styles('.__YHBToolStyleDebugConsole-body label', {
      display: 'flex',
      marginLeft: '5px'
    })
    css.styles('.__YHBToolStyleDebugConsole-body select', {
      outline: 'unset',
      marginLeft: '10px',
      border: 'none',
      borderRadius: '3px',
      width: '70px',
      textAlign: 'center'
    })
    css.styles('.__YHBToolStyleDebugConsole-body .one select', {
      width: '120px'
    })
    css.styles('.__YHBToolStyleDebugConsole-body input', {
      outline: 'unset',
      marginLeft: '10px',
      border: 'none',
      borderRadius: '3px',
      padding: '0px 2px 0px 2px',
      width: '55px'
    })
    css.styles(".__YHBToolStyleDebugConsole-body [name='margin']", {
      width: '100px'
    })
    css.styles(".__YHBToolStyleDebugConsole-body [name='padding']", {
      width: '100px'
    })
    css.styles(
      ".__YHBToolStyleDebugConsole-body [name='transformData']",
      {
        width: '150px'
      }
    )
    css.styles(
      ".__YHBToolStyleDebugConsole-body [name='transformType']",
      {
        width: '100px'
      }
    )
    css.styles('.__YHBToolStyleDebugConsole-body button', {
      position: 'absolute',
      border: 'none',
      borderRadius: '5px',
      padding: '5px',
      top: '9px',
      backgroundColor: '#00ff68',
      left: '100px',
      zIndex: 1
    })
    _getStyle(element)
  }
}
/**
 * 私有函数，请勿调用
 */
function _getStyle (element) {
  const styleForm = document.getElementById(
    '__YHBToolStyleDebugConsole-form'
  )
  form.HTML(styleForm, ({ text, select }) => {
    let str = `${element} {<br/>`
    for (const key in text) {
      if (
        text[key] &&
        key !== 'borderPx' &&
        key !== 'borderColor' &&
        key !== 'transformData'
      ) {
        str += `&nbsp&nbsp ${key}:${text[key]};<br/>`
      }
    }
    for (const key in select) {
      if (
        select[key] !== 0 &&
        key !== 'borderType' &&
        key !== 'transformType'
      ) {
        str += `&nbsp&nbsp ${key}:${select[key]};<br/>`
      }
    }
    if (text.borderPx) {
      if (select.borderType !== 0) {
        str += `&nbsp&nbsp border:${text.borderPx} ${select.borderType} ${text.borderColor};<br/>`
      } else {
        str += `&nbsp&nbsp border:${text.borderPx} solid ${text.borderColor};<br/>`
      }
    }
    if (text.transformData) {
      if (select.transformType !== 0) {
        str += `&nbsp&nbsp transform:${select.transformType}(${text.transformData});<br/>`
      }
    }
    str += '}'
    if (
      document.querySelector('.__YHBToolStyleDebugConsoleFormData')
    ) {
      document
        .querySelector('.__YHBToolStyleDebugConsoleFormData')
        .remove()
    }
    const div = document.createElement('p')
    div.classList.add('__YHBToolStyleDebugConsoleFormData')
    const button = document.createElement('div')
    div.innerHTML = str
    div.prepend(button)
    css.style(div, {
      position: 'fixed',
      zIndex: '99999999999999999999999999999999999',
      width: '260px',
      height: '300px',
      backgroundColor: 'rgb(74 74 74 / 83%)',
      borderRadius: '10px',
      top: '30%',
      left: '50%',
      transform: 'translate(-50%,-50%)',
      color: '#fff',
      padding: '30px 10px 10px 10px',
      boxSizing: 'border-box',
      overflowWrap: 'break-word',
      overflowY: 'auto'
    })
    css.style(button, {
      position: 'absolute',
      width: '12px',
      height: '12px',
      backgroundColor: '#ff5a5a',
      borderRadius: '50%',
      top: '7px',
      right: '5px'
    })
    document.body.appendChild(div)
    Listener(button, 'click', () => {
      div.remove()
    })
  })
}
/**
 * 私有函数，请勿调用
 */
function _change (element, name) {
  const nameEle = document.querySelector(`[name="${name}"]`)
  if (nameEle.value && nameEle.value !== 0) {
    document.querySelectorAll(element).forEach(item => {
      item.style[name] = nameEle.value
    })
  } else {
    document.querySelectorAll(element).forEach(item => {
      item.style[name] = ''
    })
  }
}
/**
 * 私有函数，请勿调用
 */
function _borderChange (element) {
  const borderPx = document.querySelector('[name="borderPx"]')
  const borderType = document.querySelector('[name="borderType"]')
  const borderColor = document.querySelector('[name="borderColor"]')
  const ele = document.querySelectorAll(element)
  ele.forEach(item => {
    if (borderPx.value) {
      if (borderType.value !== 0) {
        item.style.border = `${borderPx.value} ${borderType.value} ${borderColor.value}`
      } else {
        item.style.border = `${borderPx.value} solid ${borderColor.value}`
      }
    } else {
      item.style.border = ''
    }
  })
}
/**
 * 私有函数，请勿调用
 */
function _transformChange (element) {
  const transformType = document.querySelector(
    '[name="transformType"]'
  )
  const transformData = document.querySelector(
    '[name="transformData"]'
  )
  const ele = document.querySelectorAll(element)
  if (transformType.value === 'translate') {
    transformData.placeholder = '位移'
  } else if (transformType.value === 'translateX') {
    transformData.placeholder = '横向位移'
  } else if (transformType.value === 'translateY') {
    transformData.placeholder = '纵向位移'
  } else if (transformType.value === 'rotate') {
    transformData.placeholder = '旋转(角度单位:deg)'
  } else if (transformType.value === 'scale') {
    transformData.placeholder = '缩放'
  } else if (transformType.value === 'skew') {
    transformData.placeholder = '倾斜(角度单位:deg)'
  } else transformData.placeholder = ''
  ele.forEach(item => {
    if (transformData.value) {
      if (transformType.value !== 0) {
        item.style.transform = `${transformType.value}(${transformData.value})`
      } else {
        item.style.transform = ''
      }
    } else {
      item.style.transform = ''
    }
  })
}
/**
 * 实现元素随鼠标的拖拽而移动位置
 * @param {元素或元素的css选择器} element
 */
function drag (element) {
  const ele = existElement(element, '未找到元素(drag):')
  if (ele[0]) {
    ele[1].onmousedown = function (e) {
      const boxLeft = e.offsetX
      const boxTop = e.offsetY
      document.onmousemove = function (e) {
        ele[1].style.position = 'absolute'
        ele[1].style.transform = ''
        ele[1].style.left = e.clientX - boxLeft + 'px'
        ele[1].style.top = e.clientY - boxTop + 'px'
      }
      document.onmouseup = function () {
        document.onmousemove = null
      }
    }
  }
}

/**
 * 禁止选中该元素的文本内容
 * @param {元素或元素的css选择器} element
 */
function prohibitSelection (element) {
  const ele = existElement(element, '未找到元素(prohibitSelection):')
  if (ele[0]) {
    if (typeof ele[1].onselectstart !== 'undefined') {
      ele[1].onselectstart = () => false
    } else if (typeof ele[1].style.MozUserSelect !== 'undefined') {
      ele[1].style.MozUserSelect = 'none'
    } else {
      ele[1].onmousedown = () => false
    }
  }
}

/**
 * 路径管理，可以管理使用的路径
 * Path.Summary可以获取全部存储的路径
 * @param {路径对象} pathName
 */
class Path {
  constructor (pathName = {}) {
    if (
      Object.prototype.toString.call(pathName) !== '[object Object]'
    ) {
      return
    }
    if (!this.basePath) this.basePath = ''
    if (!this.secondPath) this.secondPath = ''
    this.Summary = {}
    this.Initial = pathName
    for (const key in pathName) {
      this[key] = this.basePath + this.secondPath + pathName[key]
      this.Summary[key] =
        this.basePath + this.secondPath + pathName[key]
    }
  }

  /**
   * 增加路径
   * @param {路径名} name
   * @param {具体路径} value
   */
  add (name = '', value = '') {
    if (!this[name]) {
      this[name] = this.basePath + this.secondPath + value
      this.Summary[name] = this.basePath + this.secondPath + value
      this.Initial[name] = value
    }
  }

  /**
   * 修改路径
   * @param {需要修改的路径名} name
   * @param {更新后的具体路径名} value
   */
  modify (name = '', value = '') {
    if (this[name]) {
      this[name] = this.basePath + this.secondPath + value
      this.Summary[name] = this.basePath + this.secondPath + value
      this.Initial[name] = value
    }
  }

  /**
   * 删除路径
   * @param {需要删除的路径名} name
   */
  del (name = '') {
    delete this[name]
  }

  /**
   * 获取后缀名，默认获取对象的全部后缀名
   * @param {需要拿取后缀名的路径名} name
   */
  suffix (name = '') {
    const suffixObj = {}
    if (name === '') {
      for (const key in this.Summary) {
        const value = this.Summary[key]
        if (value.lastIndexOf('.') !== -1) {
          suffixObj[key] = value.substring(
            value.lastIndexOf('.') + 1,
            value.length
          )
        } else suffixObj[key] = undefined
      }
    } else {
      if (this[name]) {
        const value = this[name]
        suffixObj[name] = value.substring(
          value.lastIndexOf('.') + 1,
          value.length
        )
      } else return
    }
    return suffixObj
  }

  /**
   * 设置公共前置路径
   * @param {公共前置路径} basePath String
   */
  setBasePath (basePath = '') {
    this.basePath = basePath
    for (const key in this.Initial) {
      this[key] = this.basePath + this.secondPath + this.Initial[key]
      this.Summary[key] =
        this.basePath + this.secondPath + this.Initial[key]
    }
  }

  /**
   * 设置第二层公共前置路径，会拼接在basePath之后
   * @param {第二层公共前置路径} basePath String
   */
  setSecondPath (secondPath = '') {
    this.secondPath = secondPath
    for (const key in this.Initial) {
      this[key] = this.basePath + this.secondPath + this.Initial[key]
      this.Summary[key] =
        this.basePath + this.secondPath + this.Initial[key]
    }
  }
}

/**
 * 获取路径字符串的后缀名
 * @param {路径字符串} path String
 * @returns String||undefined
 */
function getSuffix (path) {
  if (Object.prototype.toString.call(path) !== '[object String]') {
    return
  }
  if (path.lastIndexOf('.') !== -1) {
    return path.substring(path.lastIndexOf('.'), path.length)
  }
}

/**
 * 判断元素是否显示在页面上,使用位移移动到页面外不会被检测为false
 * @param {css选择器或者元素} element
 * @returns Boolean
 */
function isElementDisplay (element = '') {
  if (element === '' || element === null || element === undefined) {
    return false
  } else {
    if (element === 'window') {
      return true
    } else {
      element =
        typeof element === 'string'
          ? document.querySelector(element)
          : element
      if (!element) return false
      else if (!element.localName) {
        return true
      } else if (
        element.localName &&
        (element.localName === 'html' || element.localName === 'body')
      ) {
        return true
      } else {
        const style = window.getComputedStyle(element)
        const transform = style.transform
        if (style.display === 'none') return false
        else if (style.opacity === 0) return false
        else if (
          /^matrix\(0, .+, .+, 0, .+, .+\)$/.test(transform) ||
          /^matrix\(1, .+, .+, 0, .+, .+\)$/.test(transform) ||
          /^matrix\(0, .+, .+, 1, .+, .+\)$/.test(transform)
        ) {
          return false
        } else if (
          /^matrix\(0\.[1-9], .+, .+, 0\.[1-9], .+, .+\)$/.test(
            transform
          ) ||
          /^matrix\(0\.[0-9][1-9], .+, .+, 0\.[0-9][1-9], .+, .+\)$/.test(
            transform
          )
        ) {
          return false
        } else if (style.visibility === 'hidden') return false
        else {
          const parent = element.parentNode
          if (parent.localName === 'body') {
            return true
          } else {
            return isElementDisplay(parent)
          }
        }
      }
    }
  }
}

/**
 * 类型判断类
 */
const Is = {
  /**
   * 判断数据是否为数字
   * @param {数据} data
   * @returns Boolean
   */
  Number: function (data) {
    if (Object.prototype.toString.call(data) === '[object Number]') {
      return true
    } else return false
  },
  /**
   * 判断数据是否为非NaN的数字
   * @param {数据} data
   * @returns Boolean
   */
  ValidNumber: function (data) {
    if (Object.prototype.toString.call(data) !== '[object Number]') {
      return false
    }
    if (isNaN(data)) return false
    else return true
  },
  /**
   * 判断数据是否为整数
   * @param {数据} data
   * @returns Boolean
   */
  Int: function (data) {
    if (Object.prototype.toString.call(data) !== '[object Number]') {
      return false
    }
    if (isNaN(data)) return false
    const pointIndex = data.toString().indexOf('.')
    if (
      pointIndex !== -1 &&
      pointIndex !== data.toString().length - 1
    ) {
      return false
    } else return true
  },
  /**
   * 判断数据是否为浮点
   * @param {数据} data
   * @returns Boolean
   */
  Float: function (data) {
    if (Object.prototype.toString.call(data) !== '[object Number]') {
      return false
    }
    if (isNaN(data)) return false
    const pointIndex = data.toString().indexOf('.')
    if (
      pointIndex !== -1 &&
      pointIndex !== data.toString().length - 1
    ) {
      return true
    } else return false
  },
  /**
   * 判断数据是否为布尔
   * @param {数据} data
   * @returns Boolean
   */
  Boolean: function (data) {
    if (Object.prototype.toString.call(data) === '[object Boolean]') {
      return true
    } else return false
  },
  /**
   * 判断数据是否为字符串
   * @param {数据} data
   * @returns Boolean
   */
  String: function (data) {
    if (Object.prototype.toString.call(data) === '[object String]') {
      return true
    } else return false
  },
  /**
   * 判断数据是否为函数
   * @param {数据} data
   * @returns Boolean
   */
  Function: function (data) {
    if (
      Object.prototype.toString.call(data) === '[object Function]'
    ) {
      return true
    } else return false
  },
  /**
   * 判断数据是否为数组
   * @param {数据} data
   * @returns Boolean
   */
  Array: function (data) {
    if (Object.prototype.toString.call(data) === '[object Array]') {
      return true
    } else return false
  },
  /**
   * 判断数据是否为伪数组
   * @param {数据} data
   * @returns Boolean
   */
  NodeList: function (data) {
    if (
      Object.prototype.toString.call(data) === '[object NodeList]'
    ) {
      return true
    } else return false
  },
  /**
   * 判断数据是否为对象
   * @param {数据} data
   * @returns Boolean
   */
  Object: function (data) {
    if (Object.prototype.toString.call(data) === '[object Object]') {
      return true
    } else return false
  },
  /**
   * 判断数据是否为时间对象
   * @param {数据} data
   * @returns Boolean
   */
  Date: function (data) {
    if (Object.prototype.toString.call(data) === '[object Date]') {
      return true
    } else return false
  },
  /**
   * 判断数据是否为正则
   * @param {数据} data
   * @returns Boolean
   */
  Reg: function (data) {
    if (Object.prototype.toString.call(data) === '[object RegExp]') {
      return true
    } else return false
  },
  /**
   * 判断数据是否为undefined
   * @param {数据} data
   * @returns Boolean
   */
  Undefined: function (data) {
    if (data === undefined) return true
    else return false
  },
  /**
   * 判断数据是否为Symbol
   * @param {数据} data
   * @returns Boolean
   */
  Symbol: function (data) {
    if (Object.prototype.toString.call(data) === '[object Symbol]') {
      return true
    } else return false
  },
  /**
   * 判断数据是否为页面元素
   * @param {数据} data
   * @returns Boolean
   */
  Element: function (data) {
    if (
      Object.prototype.toString.call(data) ===
      '[object HTMLButtonElement]'
    ) {
      return true
    } else return false
  },
  /**
   * 判断数据是否为null
   * @param {数据} data
   * @returns Boolean
   */
  Null: function (data) {
    if (Object.prototype.toString.call(data) === '[object Null]') {
      return true
    } else return false
  },
  /**
   * 判断数据是否为NaN
   * @param {数据} data
   * @returns Boolean
   */
  NaN: function (data) {
    if (isNaN(data)) return true
    else return false
  },
  /**
   * 判断数据是否为JSON
   * @param {数据} data
   * @returns Boolean
   */
  JSON: function (data) {
    try {
      const json = JSON.parse(data)
      if (
        Object.prototype.toString.call(json) === '[object Object]'
      ) {
        return true
      }
    } catch {
      return false
    }
  },
  /**
   * 判断数据是否为Promise
   * @param {数据} data
   * @returns Boolean
   */
  Promise: function (data) {
    if (Object.prototype.toString.call(data) === '[object Promise]') {
      return true
    } else return false
  },
  /**
   * 判断数据是否为Error
   * @param {数据} data
   * @returns Boolean
   */
  Error: function (data) {
    if (Object.prototype.toString.call(data) === '[object Error]') {
      return true
    } else return false
  },
  /**
   * 判断数据是否为Arguments
   * @param {数据} data
   * @returns Boolean
   */
  Arguments: function (data) {
    if (
      Object.prototype.toString.call(data) === '[object Arguments]'
    ) {
      return true
    } else return false
  },
  /**
   * 判断是否为空对象
   * @param {需要判断的对象} obj Object
   * @returns Boolean
   */
  EmptyObj: function (obj = {}) {
    if (
      !(Object.prototype.toString.call(obj) === '[object Object]')
    ) {
      return undefined
    }
    return JSON.stringify(obj) === '{}'
  },
  /**
   * 判断是否为空数组
   * @param {需要判断的数组} arr Array
   * @returns Boolean
   */
  EmptyArr: function (arr = []) {
    if (!(arr instanceof Array)) return undefined
    return arr.length === 0
  }
}

/**
 * 获取数据类型
 * @param {数据} data
 * @returns string
 */
function getDataType (data) {
  const type = Object.prototype.toString.call(data) + ''
  return type.substring(type.indexOf(' ') + 1, type.length - 1)
}

/**
 * 数组方法
 */
const Arr = {
  /**
   * 根据condition字符串，来判断arr数组每一项是否满足条件
   * 如果reverse为true，返回满足条件的每一项
   * 如果reverse为false，返回不满足条件的每一项
   * @param {需要判断的数组} arr Array
   * @param {判断数组中每一项是否与参数一致} condition String
   * @param {是否反向输出} reverse Boolean
   * @param {回调函数} callback Function
   * @param {回调函数参数_条件判断后新的数组} callback_newArr Array
   * @returns Array
   */
  getFilter: function (
    arr = [],
    condition = '',
    reverse = true,
    callback = function (newArr) {}
  ) {
    const newArr = []
    if (reverse) {
      arr.forEach(item => {
        item === condition && newArr.push(item)
      })
    } else {
      arr.forEach(item => {
        item !== condition && newArr.push(item)
      })
    }
    callback(newArr)
    return newArr
  },
  /**
   * 根据condition字符串，来判断arr数组满足条件的个数
   * 如果reverse为true，返回满足条件的个数
   * 如果reverse为false，返回不满足条件的个数
   * @param {需要判断的数组} arr Array
   * @param {判断数组中每一项是否与参数一致} condition Object
   * @param {是否反向输出} reverse Boolean
   * @returns Number
   */
  getFilterNum: function (arr = [], condition = '', reverse = true) {
    let newNum = 0
    if (reverse) {
      arr.forEach(item => {
        item === condition && ++newNum
      })
    } else {
      arr.forEach(item => {
        item !== condition && ++newNum
      })
    }
    return newNum
  },
  /**
   * 根据condition对象，来判断arr数组每一项的对象是否满足条件
   * 如果reverse为true，返回满足条件的每一项
   * 如果reverse为false，返回不满足条件的每一项
   * @param {需要判断的对象数组} arr Array
   * @param {判断对象数组中属性名指向的值是否与本对象一致} condition Object
   * @param {是否反向输出} reverse Boolean
   * @param {回调函数} callback Function
   * @param {回调函数参数_条件判断后新的数组} callback_newArr Array
   * @returns Array
   */
  getObjFilter: function (
    arr = [],
    condition = {},
    reverse = true,
    callback = function (newArr) {}
  ) {
    const newArr = []
    if (reverse) {
      arr.forEach(item => {
        let mate = true
        for (const key in condition) {
          if (item[key]) {
            if (item[key] !== condition[key]) {
              mate = false
              break
            }
          } else {
            mate = false
            break
          }
        }
        mate && newArr.push(item)
      })
    } else {
      arr.forEach(item => {
        let mate = true
        for (const key in condition) {
          if (item[key]) {
            if (item[key] === condition[key]) {
              mate = false
              break
            }
          } else {
            mate = false
            break
          }
        }
        mate && newArr.push(item)
      })
    }
    callback(newArr)
    return newArr
  },
  /**
   * 根据condition对象，来判断arr数组的对象满足条件的个数
   * 如果reverse为true，返回满足条件的个数
   * 如果reverse为false，返回不满足条件的个数
   * @param {需要判断的对象数组} arr Array
   * @param {判断对象数组中属性名指向的值是否与本对象一致} condition Object
   * @param {是否反向输出} reverse Boolean
   * @returns Number
   */
  getObjFilterNum: function (
    arr = [],
    condition = {},
    reverse = true
  ) {
    let newNum = 0
    if (reverse) {
      arr.forEach(item => {
        let mate = true
        for (const key in condition) {
          if (item[key]) {
            if (item[key] !== condition[key]) {
              mate = false
              break
            }
          } else {
            mate = false
            break
          }
        }
        mate && ++newNum
      })
    } else {
      arr.forEach(item => {
        let mate = true
        for (const key in condition) {
          if (item[key]) {
            if (item[key] === condition[key]) {
              mate = false
              break
            }
          } else {
            mate = false
            break
          }
        }
        mate && ++newNum
      })
    }
    return newNum
  },
  /**
   * 单项中的值计算
   * 根据属性名，遍历arr中每一项的对象，并求出该属性名对应值的和
   * 数组中的非对象会被忽略
   * 对象中该属性的值非数字或为NaN会被忽略
   * @param {对象数组} arr
   * @param {需要求和的对象属性名} key
   * @returns Number
   */
  getObjSum: function (arr = [], key = '') {
    let sum = 0
    arr.forEach(item => {
      if (Is.Object(item)) {
        Is.ValidNumber(item[key]) && (sum += item[key])
      }
    })
    return sum
  },
  /**
   * 单项中的值计算
   * 根据属性名，遍历arr中每一项的对象，求出该属性名对应值的和，并根据数量计算出平均值
   * 数组中的非对象会被忽略
   * 对象中该属性的值非数字或为NaN会被忽略
   * @param {对象数组} arr Array
   * @param {需要求平均值的对象属性名} key String
   * @param {需要保留的位数} places Number
   * @returns Number
   */
  getObjAverage: function (arr = [], key = '', places = -1) {
    let sum = 0
    let num = 0
    arr.forEach(item => {
      if (Is.Object(item) && Is.ValidNumber(item[key])) {
        sum += item[key]
        num++
      }
    })
    const res = num ? sum / num : 0
    return places === -1 ? res : res.toFixed(places)
  },
  /**
   * 项与项之间的计算
   * keys数组中的全部值为对象属性名，对arr数组中每一项的对象进行属性名匹配
   * 并根据type的计算类型，将对象中的每一个属性进行同等计算操作
   * 然后循环到arr的下一个对象项，继续计算
   * 最后返回包含每个对象计算结果的数组
   * type的取值有：add（默认）加法；sub减法；mul乘法；div除法
   * @param {对象数组} arr
   * @param {需要被计算的对象属性名数组} keys
   * @param {计算类型} type
   * @returns Array
   */
  getObjCount: function (arr = [], keys = [], type = 'add') {
    type = type.toLowerCase()
    const resArr = []
    arr.forEach(item => {
      const value = []
      keys.forEach(itemKey => {
        value.push(item[itemKey])
      })
      let res = value[0]
      value.forEach((itemValue, index) => {
        if (index) {
          if (type === 'add') res += itemValue
          else if (type === 'sub') res -= itemValue
          else if (type === 'mul') res *= itemValue
          else if (type === 'div') res /= itemValue
        }
      })
      resArr.push(res)
    })
    return resArr
  },
  /**
   * 寻找对象数组中每一个符合key属性的值
   * 返回新数组，每一项为对应的值
   * @param {对象数组} arr Array
   * @param {属性名} key String
   * @returns Array
   */
  getObjValue: function (arr = [], key = '') {
    return arr.map(item => {
      return item[key]
    })
  },
  /**
   * 根据keys的键值对，删除arr对象数组中的匹配项
   * 返回删除后的对象数组
   * @param {对象数组} arr Array
   * @param {需要删除的对象键值对} keys Object
   * @param {回调函数} callback Function
   * @param {回调函数参数_包含所有被删除对象的数组} callback_delItem Array
   * @returns Array
   */
  delObjItem: function (
    arr = [],
    keys = {},
    callback = function (delItem) {}
  ) {
    const tempArr = []
    const delItem = []
    arr.forEach(item => {
      for (const key in keys) {
        if (item[key] && item[key] !== keys[key]) tempArr.push(item)
        else delItem.push(item)
      }
    })
    callback(delItem)
    return tempArr
  },
  /**
   * 根据KeyValuePair里面的键值对，匹配arr对象数组的每一项
   * 将每一项匹配到的属性名都改为替换值
   * 返回新对象数组
   * @param {需要处理的对象数组} arr Array
   * @param {储存属性名与替换值的键值对} KeyValuePair Object
   * @returns Array
   */
  replaceObjItem: function (arr = [], KeyValuePair = {}) {
    const temp = []
    if (!Is.Array(arr)) return
    arr.forEach(item => {
      const tempItem = item
      if (Is.Object(item)) {
        for (const key in KeyValuePair) {
          if (tempItem[key]) {
            tempItem[key] = KeyValuePair[key]
          }
        }
      }
      temp.push(tempItem)
    })
    return temp
  },
  /**
   * 专门用于对对象数组进行计算的方法
   * @param {需要计算的对象数组} arr 
   * @param {计算表达式} separate 
   * @param {整体操作指令} whole 
   * @param {回调函数} callback 
   * @returns 
   */
  objComputing:function(arr = [], separate = '', whole = 'add', callback = function () { }) { 
    if (!Is.Array(arr)) return
    if (!/\$.+\$/.test(separate)) return
    if (whole==="") return
    let tempArr = separate.split("")
    const newArr = arr.map(arrItem => {
      let v = ""
      let str = ""
      let is = false
      tempArr.forEach(item => {
        if (item === "$") is = !is
        else {
          if (is) {
            v += item
          } else {
            if (v !== "") {
              str += arrItem[v]
              if(!Is.Number(arrItem[v]))return
              str += item
              v = ""
            }
            else str += item
          }
        }
      })
      if(!Is.Number(arrItem[v]))return
      if (v !== "") str += arrItem[v]
      return new Function(`return ${str}`)()
    })
    
    let res = newArr[0]
    whole = whole.toLocaleLowerCase()
    whole = Str.removeAllSpace(whole)
    if (whole === 'add' || whole === '+') {
      newArr.forEach((item, index) => { if (index) res += item })
      callback(newArr)
      return res
    }
    else if (whole === 'sub' || whole === '-') {
      newArr.forEach((item, index) => { if (index) res -= item })
      callback(newArr)
      return res
    }
    else if (whole === 'mul' || whole === '*') {
      newArr.forEach((item, index) => { if (index) res *= item })
      callback(newArr)
      return res
    }
    else if (whole === 'div' || whole === '/') {
      newArr.forEach((item, index) => { if (index) res /= item })
      callback(newArr)
      return res
    }
    else if (whole === 'avg') {
      newArr.forEach((item, index) => { if (index) res += item })
      res = res / newArr.length
      callback(newArr)
      return res
    }
    else if (whole === 'max') {
      newArr.forEach((item, index) => { if (index && item > res) res = item })
      callback(newArr)
      return res
    }
    else if (whole === 'min') {
      newArr.forEach((item, index) => { if (index && item < res) res = item })
      callback(newArr)
      return res
    }
    else if (whole === 'arr' || whole === '[]') {
      callback(newArr)
      return newArr
    }
    else {
      if (/^>=/.test(whole)) {
        const num = +whole.substring(2, whole.length)
        callback(newArr)
        return newArr.filter(item => item >= num)
      }
      else if (/^<=/.test(whole)) {
        const num = +whole.substring(2, whole.length)
        callback(newArr)
        return newArr.filter(item => item <= num)
      }
      else if (/^>/.test(whole)) {
        const num = +whole.substring(1, whole.length)
        callback(newArr)
        return newArr.filter(item => item > num)
      }
      else if (/^</.test(whole)) {
        const num = +whole.substring(1, whole.length)
        callback(newArr)
        return newArr.filter(item => item < num)
      }
      else if (/^===/.test(whole)) {
        const num = +whole.substring(3, whole.length)
        callback(newArr)
        return newArr.filter(item => item === num)
      }
      else if (/^!==/.test(whole)) {
        const num = +whole.substring(3, whole.length)
        callback(newArr)
        return newArr.filter(item => item !== num)
      }
      else if (/^==/.test(whole)) {
        const num = +whole.substring(2, whole.length)
        callback(newArr)
        return newArr.filter(item => item == num)
      }
      else if (/^!=/.test(whole)) {
        const num = +whole.substring(2, whole.length)
        callback(newArr)
        return newArr.filter(item => item != num)
      }
      else if (/^!!$/.test(whole)) {
        const num = +whole.substring(2, whole.length)
        callback(newArr)
        return newArr.map(item => !!item)
      }
      else if (/^!$/.test(whole)) {
        const num = +whole.substring(1, whole.length)
        callback(newArr)
        return newArr.map(item => !item)
      }
    }
  }
}

/**
 * 排他性类名添加
 * @param {元素伪数组或元素的css选择器或选择器数组} eleArr Array||String||Element
 * @param {需要排它的类名} className String
 * @param {事件类型} listenerType String
 * @returns
 */
function classExclusive (
  eleArr = [],
  className = '',
  listenerType = 'click'
) {
  if (Object.prototype.toString.call(eleArr) === '[object Array]') {
    if (eleArr.length === 0) return
    if (className.substring(0, 1) !== '.') {
      className = '.' + className
    }
    eleArr.forEach(item => {
      Listener(item, listenerType, () => {
        const cName = className.substring(1, className.length)
        const haveClass = document.querySelectorAll(className)
        if (haveClass.length !== 0) {
          haveClass.forEach(item => {
            item.classList.remove(cName)
          })
        }
        item.classList.add(cName)
      })
    })
  } else if (
    Object.prototype.toString.call(eleArr) === '[object String]'
  ) {
    const ele = existElements(
      eleArr,
      '全选元素不存在(classExclusive)'
    )
    if (!ele[0]) return
    ele[1].forEach(item => {
      Listener(item, listenerType, () => {
        const cName = className.substring(1, className.length)
        const haveClass = document.querySelectorAll(className)
        if (haveClass.length !== 0) {
          haveClass.forEach(item => {
            item.classList.remove(cName)
          })
        }
        item.classList.add(cName)
      })
    })
  } else if (
    Object.prototype.toString.call(eleArr) === '[object NodeList]'
  ) {
    eleArr.forEach(item => {
      Listener(item, listenerType, () => {
        const cName = className.substring(1, className.length)
        const haveClass = document.querySelectorAll(className)
        if (haveClass.length !== 0) {
          haveClass.forEach(item => {
            item.classList.remove(cName)
          })
        }
        item.classList.add(cName)
      })
    })
  }
}

/**
 * 依次对传入的数组中的方法或表达式进行计算，并将计算结果自动传入下一个方法的第一个参数
 * 或将值传给下一个表达式中的 $val$ 表达式中
 * @param {方法或表达式的数组} Methods_Expressions Array
 * @param {回调函数} callback Function
 * @returns data
 */
function parameterPassing (
  Methods_Expressions = [],
  callback = function (values) {}
) {
  if (
    Object.prototype.toString.call(Methods_Expressions) !==
    '[object Array]'
  ) {
    return
  }
  const valueArr = []
  Methods_Expressions.forEach((item, index) => {
    if (index === 0) {
      if (Is.Function(item)) {
        valueArr.push(item())
      } else {
        valueArr.push(evalSimulate(item))
      }
    } else {
      if (Is.Function(item)) {
        valueArr.push(item(valueArr[index - 1]))
      } else if (Is.String(item) && /\$val\$/.test(item)) {
        while (/\$val\$/.test(item)) {
          item = item.replace('$val$', valueArr[index - 1])
        }
        valueArr.push(evalSimulate(item))
      } else if (Is.Array(item)) {
        const temp = []
        item.forEach(i => {
          if (/\$val\$/.test(i)) {
            while (/\$val\$/.test(i)) {
              i = i.replace('$val$', valueArr[index - 1])
            }
            temp.push(valueArr[index - 1])
          } else temp.push(i)
        })
        valueArr.push(temp)
      } else if (Is.Object(item)) {
        const temp = {}
        for (let key in item) {
          let tempValue = item[key]
          if (/\$val\$/.test(tempValue)) {
            while (/\$val\$/.test(tempValue)) {
              tempValue = tempValue.replace(
                '$val$',
                valueArr[index - 1]
              )
            }
          }
          if (/\$val\$/.test(key)) {
            key = key + ''
            while (/\$val\$/.test(key)) {
              key = key.replace('$val$', valueArr[index - 1])
            }
            temp[key] = tempValue
          } else temp[key] = tempValue
        }
        valueArr.push(temp)
      } else {
        valueArr.push(evalSimulate(item))
      }
    }
  })
  callback(valueArr)
  return valueArr[valueArr.length - 1]
}

let __YHBToolAntiShakeOverallInternalTimeout = null
let __YHBToolAntiShakeOverallInternalTimeoutTime = 700

/**
 * 将函数包装为局部防抖函数
 * @param {需要修饰的函数} protectFunction Function
 * @param {防抖时间_默认700毫秒} time Number
 * @returns Function
 */
function antiShake (
  protectFunction = function () {},
  time = 700
) {
  let __AntiShakeInternalTimeout = null
  return function fn () {
    clearTimeout(__AntiShakeInternalTimeout)
    __AntiShakeInternalTimeout = setTimeout(() => {
      protectFunction()
    }, time)
  }
}
/**
 * 将函数包装为全局防抖函数
 * 每个调用此方法的函数，都将共享防抖
 * @param {需要修饰的函数} protectFunction Function
 * @returns Function
 */
function antiShakeOverall (protectFunction = function () {}) {
  return function fn () {
    clearTimeout(__YHBToolAntiShakeOverallInternalTimeout)
    __YHBToolAntiShakeOverallInternalTimeout = setTimeout(() => {
      protectFunction()
    }, __YHBToolAntiShakeOverallInternalTimeoutTime)
  }
}
/**
 * 设置全局防抖的时间
 * 默认700毫秒
 * @param {防抖时间} time Number
 */
function setAntiShakeTime (time = 700) {
  __YHBToolAntiShakeOverallInternalTimeoutTime = time
}

let __YHBToolThrottleOverallIsStart = true
let __YHBToolThrottleOverallTime = 1000

/**
 * 将函数包装为局部节流
 * 每个调用此方法的函数都将独立节流
 * @param {需要修饰的函数} protectFunction Function
 * @param {节流时间_默认1000毫秒} time Number
 * @returns Function
 */
function throttle (
  protectFunction = function () {},
  time = 1000
) {
  let __ThrottleIsStart = true
  return function () {
    if (!__ThrottleIsStart) return
    __ThrottleIsStart = false
    setTimeout(() => {
      protectFunction()
      __ThrottleIsStart = true
    }, time)
  }
}

/**
 * 将函数包装为全局节流
 * 每个调用此方法的函数都将共享节流
 * 节流时间需要通过setThrottleTime来进行设置
 * 默认节流时间为1000毫秒
 * @param {需要修饰的函数} protectFunction Function
 * @returns Function
 */
function throttleOverall (protectFunction = function () {}) {
  return function () {
    if (!__YHBToolThrottleOverallIsStart) return
    __YHBToolThrottleOverallIsStart = false
    setTimeout(() => {
      protectFunction()
      __YHBToolThrottleOverallIsStart = true
    }, __YHBToolThrottleOverallTime)
  }
}
/**
 * 设置全局节流的时间
 * 默认1000毫秒
 * @param {节流时间} time
 */
function setThrottleTime (time = 1000) {
  __YHBToolThrottleOverallTime = time
}

/**
 * 将参数对象内部的每一项都定义为全局变量或方法
 * 方便统一管理
 * 定义常量时，利用const对象进行创建
 * @param {变量对象} variables Object
 * @returns {变量对象} Object
 */
function globalVariables (variables = { const: {} }) {
  if (!Is.Object(variables) || Is.EmptyObj(variables)) return
  let keys = []
  let constObj = {}
  for (const key in variables) {
    if (key === 'const') {
      constObj = variables.const
    } else {
      keys.push(key)
      Object.defineProperty(window, key, {
        value: variables[key],
        configurable: false,
        writable: true,
        enumerable: false
      })
    }
  }
  if (Is.Object(constObj) && !Is.EmptyObj(constObj)) {
    for (const key in constObj) {
      keys.forEach(item => {
        if (item === key) {
          throw new Error(`定义同名(globalVariables)：\n
    定义全局常量 ${key} 时发生错误！
    已有同名全局变量 ${item}\n

    结构：globalVariables {
        ...
    --> ${item} : ${variables[item]}
        ...
      const: {
          ...
      --> ${key}:${constObj[key]}
          ...
      }
    }\n`)
        }
      })
      Object.defineProperty(window, key, {
        value: variables.const[key],
        configurable: false,
        writable: false,
        enumerable: false
      })
    }
  }
  keys = null
  constObj = null
  return variables
}

/**
 * 将字符串解析成语句进行执行
 * @param {需要执行的字符串} str
 * @returns
 */
const evalSimulate = function (str = '') {
  const FnTemp = Function
  try {
    return new FnTemp(`return ${str}`)()
  } catch (error) {
    throw new Error(
      '执行错误(evalSimulate)：\n\n您输入的字符串为：' + str + '\n'
    )
  }
}

/* 存储库中所有的方法、对象与构造函数 */
const __YHBModules = {
  SwitchToMobile,
  SwitchToComputer,
  userInput,
  log,
  dir,
  err,
  dq,
  dqa,
  $Log,
  formatSecond,
  Digit,
  Str,
  Char,
  Color,
  Timer,
  FormatDate,
  Net,
  Modal,
  form,
  css,
  Listener,
  Listeners,
  AllListener,
  eventsListener,
  renderContent,
  singleLayer,
  local,
  session,
  cookie,
  toUrl,
  MapTable,
  randomToken,
  charArr,
  Module,
  drag,
  Path,
  getSuffix,
  isElementDisplay,
  Is,
  getDataType,
  Arr,
  classExclusive,
  parameterPassing,
  antiShake,
  antiShakeOverall,
  setAntiShakeTime,
  throttle,
  throttleOverall,
  setThrottleTime,
  globalVariables,
  evalSimulate
}
/* 向Vue原型方法中进行注册，库中的方法可以使用this.来进行调用了 */
const YHB = {
  install (Vue) {
    for (const key in __YHBModules) {
      const fKey = "$" + key.toLowerCase()
      Vue.prototype[fKey] = __YHBModules[key]
    }
  }
}
